
######################################################################
#
#  AFTERSTEP.PL - WM-specific code file for wmtheme
#

use Socket;

$tosite = 'as.themes.org';
$wm_executable = 'afterstep';
$dont_extract = 1;
$badnamechars .= '"`';

my $afterstep_socket_name = '';
my $gsroot = $ENV{GNUSTEP_USER_ROOT} || "$home/GNUstep";
my $as_defaultlocaldir = "$gsroot/Library/AfterStep/themes";
my $as_version;

  ###
  #
  #  WM_GETDEFAULTDIRS
  #
  ###

sub wm_getdefaultdirs {
  verify_themedirs(0,
    '/usr/local/share/afterstep/themes',    #  DEFAULT
    '/usr/share/afterstep/themes',          #  Debian (probably)
    $as_defaultlocaldir
    );
}

  ###
  #
  #  WM_SCANDIR
  #
  ##

sub wm_scandir {
  my @dirs = @_;
  my ($dir, %scanned, $owner);

  while ($dir = pop @dirs) {
    dbugout("scanning $dir") if $debug;
    $owner = (stat $dir)[4];
    $scanned{$dir} = (stat _)[9];
    unless (opendir DH, $dir) {
      complain "can't read directory $dir: $!";
      next;
    }
    while (defined($entry = readdir DH)) {
      next if $entry =~ /^\.\.?$/;

      if (-d "$dir/$entry") {
        dbugout("\"$entry\" ==>> recursing into dir")
          if $debug;
        push @dirs, "$dir/$entry";
      } else {
        ($themename = $entry) =~ s/(.)\.(tgz|tar\.gz)$/$1/;
        dbugout("\"$entry\" --> theme \"$themename\"")
          if $debug;
        createthemerec($themename, "$dir/$entry", $owner);
      }
    }
    closedir DH or choke("can't closedir $dir: $!");
  }
  %scanned;
}

  ###
  #
  #  WM_INSTALLTHEME
  #
  ###

sub wm_installtheme {
  my ($location, $filename, $defname) = @_;
  my ($themename, $destthemedir);

  unless (-f $location) {
    choke("internal error: file (not directory) required for installation");
  }

  if ($filename =~ m#([^/]+?)[-\d.]*\.(tar\.gz|tgz)$#) {
    $defname ? $themename = $defname : $themename = $1;

    if ($> == 0) {
      if (!$globalthemedir) {
        choke("no global theme directory could be identified");
      }
      $destthemedir = $globalthemedir;
    } elsif (!$localthemedir and !afterstep_ensure_local_themedir()) {
      choke("no local theme directory could be identified");
    } else {
      $destthemedir = $localthemedir;
    }

    $themename = checkname($themename);
    syscmd('mv', $location, "$destthemedir/$themename.tar.gz");
    createthemerec($themename, "$destthemedir/$themename.tar.gz", $>);
    return $themename;
  } else {
    choke("can't install \"$location/$filename\": tarball required");
  }
}

  ###
  #
  #  WM_ACTIVATETHEME
  #
  ###

sub wm_activatetheme {
  my ($theme, $explicit) = @_;

  syscmd('installastheme.pl', $themes{$theme}{path});
}

  ###
  #
  #  WM_UNINSTALLTHEME
  #
  ###

sub wm_uninstalltheme {
  my $theme = shift;

  if (dirwipe($themes{$theme}{path})) {
    afterstep_reload_theme_menu();
    return 1;
  } else {
    return 0;
  }
}

  ###
  #
  #  WM_RENAME
  #
  ###

sub wm_rename {
  my ($old, $new) = @_;

  my $oldpath = $themes{$old}{path};
  my $newpath = $oldpath;

  if ($oldpath =~ /.\.(tar\.gz|tgz)$/ and -f $oldpath) {
    $newpath =~ s|[^/]+$|$new.tar.gz|;
    rename $oldpath, $newpath
      or choke("can't rename $oldpath to $newpath: $!");
    afterstep_reload_theme_menu();
    return $newpath;
  } else {
    choke("can't deal with non-tarball theme");
  }
}

  ###
  #
  #  WM_VERSIONOK
  #
  ###

sub wm_versionok {
  my $rqver = shift;
  my $asver = afterstep_version();

  if ($rqver =~ /^1\.[7](?!\d)/) {
    return $asver =~ /^1\.[78](?!\d)/
  } elsif ($rqver =~ /^1\.[6](?!\d)/) {
    return $asver =~ /^1\.[678](?!\d)/
  } else {
    return minorvermatch($rqver, $asver);
  }
}

sub afterstep_reload_theme_menu {
  afterstep_send(0, 'QuickRestart "Update startmenu" startmenu');
}


# Code after this point is shamelessly copied from ascommand.pl,
# a tool in the AfterStep 1.8.0 distribution


# AfterStep module packet format
# ------------------------------
#
# Packets are arrays of unsigned long, with a header of three elements.
# header[0] == START_FLAG (== 0xffffffff)
# header[1] == event type (as defined in include/module.h, and requested 
#                          with a SET_MASK module command)
# header[2] == number of elements in the body of the packet
#
# The content of the body of the packet is variable, depending on the 
# event type.

sub afterstep_send {
  my ($critical, @commands) = @_;
  my $assocket = afterstep_connect($critical, afterstep_get_socket_name($critical));

  if (!$assocket) {
    return unless $critical;
    choke("couldn't get a unix socket to AfterStep");
  }

  # report our name
  afterstep_send_socket($assocket, 0, "SET_NAME $programname");

  foreach (@commands) {
    afterstep_send_socket($assocket, 0, $_);
  }

  close $assocket;
}

sub afterstep_get_socket_name {
  my $critical = shift;

  if (!$afterstep_socket_name) {
    my $socket_name;

      ##  Try to get the socket name by two methods, but prefer
      ##  the opinion of `xprop`

    if ($gsroot and $ENV{DISPLAY}) {
      $socket_name = "$gsroot/Library/AfterStep/non-configurable/connect.DISPLAY=$ENV{DISPLAY}";
      $socket_name = '' unless -e $socket_name;
    }

    if ('xprop -root' =~ /^_AS_MODULE_SOCKET[^"]+"([^"]+)"/m) {
      $socket_name = $1;
    }

    unless ($socket_name) {
      return unless $critical;
      choke("can't determine AfterStep unix socket name");
    }

    $afterstep_socket_name = $socket_name;
  }
  $afterstep_socket_name;
}

# connect to AfterStep via a UNIX-domain socket

sub afterstep_connect {
  my ($critical, $socket_name) = @_;
  local *SOCKET;

  if (!socket(SOCKET, PF_UNIX, SOCK_STREAM, 0)) {
    return unless $critical;
    choke("can't get a unix socket: $!");
  }
  if (!connect(SOCKET, sockaddr_un($socket_name))) {
    return unless $critical;
    choke("can't connect to $socket_name: $!");
  }

  # set unbuffered I/O
  select((select(SOCKET), $| = 1)[0]);

  return *SOCKET;
}

  # send an AfterStep module command
  # $_[0] == socket to write command to
  # $_[1] == message to send

sub afterstep_send_socket {
  my ($fh, $linelen) = ($_[0], length($_[2]));
  print $fh pack("LLa${linelen}L", $_[1], $linelen, $_[2], 1);
}

sub afterstep_ensure_local_themedir {
  return 1 if $localthemedir;

  if (-e $as_defaultlocaldir) {
    choke("cannot proceed - a local theme directory is required, but $as_defaultlocaldir is unusable");
  } else {
    print "The directory '$as_defaultlocaldir' is required, but does not exist.\n";
    print "Create it now? (Y/n) ";
    my $answer = <STDIN>;
    if ($answer =~ /^([yY]|\s*$)/) {
      syscmd('mkdir', '-p', $as_defaultlocaldir);  # Aborts internally on failure
      $localthemedir = $as_defaultlocaldir;
      return 1;
    } else {
      choke("aborted.");
    }
  }
}

sub afterstep_version {
  if (!defined $as_version) {
    my $asv = `afterstep -v`;
    if (!$? and $asv =~ /\s([\d.]+)(?![\d.])/) {
      $as_version = $1;
    } else {
      choke("can't determine AfterStep's version");
    }
    dbugout("version was requested ($as_version)") if $debug;
  }

  $as_version;
}

1;

