package Tk::DragDrop::XDNDSite;
use strict;
use vars qw($VERSION);
$VERSION = sprintf '4.%03d', q$Revision: #6 $ =~ /\D(\d+)\s*$/;
use base qw(Tk::DropSite);

sub XDND_PROTOCOL_VERSION () { 4 }

Tk::DropSite->Type('XDND');

sub InitSite
{my ($class,$site) = @_;
 my $w = $site->widget;
}

sub XdndEnter
{
 my ($t,$sites) = @_;
 my $event = $t->XEvent;
 my ($src,$flags,@types) = unpack('LLLLL',$event->A);
 my $ver = ($flags >> 24) & 0xFF;
 if ($flags & 1)
  {
   my @prop;
   Tk::catch { @prop = $t->property('get','XdndTypeList',$src) };
   @types = @prop if (!$@ && shift(@prop) eq 'ATOM');
  }
 else
  {
   $t->MakeAtom(@types);
  }
 # print "XdndEnter $src $ver @types\n";
 $t->{"XDND$src"} = { ver => $ver, types => \@types };
}

sub XdndLeave
{
 my ($t,$sites) = @_;
 my $event = $t->XEvent;
 my ($src,$flags,@types) = unpack('LLLLL',$event->A);
 # print "XdndLeave $src\n";
 my $info = $t->{"XDND$src"};
 if ($info)
  {
   my $over = $info->{site};
   if ($over)
    {
     my $X = $info->{X};
     my $Y = $info->{Y};
     $over->Apply(-entercommand => $X, $Y, 0)
    }
  }
 delete $t->{"XDND$src"};
}

sub XdndPosition
{
 my ($t,$sites) = @_;
 my $event = $t->XEvent;
 my ($src,$flags,$xy,$time,$action) = unpack('LLLLL',$event->A);
 $t->MakeAtom($action);
 my $X = $xy >> 16;
 my $Y = $xy & 0xFFFF;
 my $info = $t->{"XDND$src"};
 $info->{X}      = $X;
 $info->{Y}      = $Y;
 $info->{action} = $action;
 $info->{t}      = $time;
 my ($id)  = $t->wrapper;
 my $sxy   = 0;
 my $swh   = 0;
 my $sflags = 0;
 my $saction = 0;
 my $over = $info->{site};
 foreach my $site (@$sites)
  {
   if ($site->Over($X,$Y))
    {
     $sxy = ($site->X << 16)     | $site->Y;
     $swh = ($site->width << 16) | $site->height;
     $saction = $action;
     $sflags |= 1;
     if ($over)
      {
       if ($over == $site)
        {
         $site->Apply(-motioncommand => $X, $Y);
        }
       else
        {
         $over->Apply(-entercommand => $X, $Y, 0);
         $site->Apply(-entercommand => $X, $Y, 1);
        }
      }
     else
      {
       $site->Apply(-entercommand => $X, $Y, 1);
      }
     $info->{site} = $site;
     last;
    }
  }
 unless ($sflags & 1)
  {
   if ($over)
    {
     $over->Apply(-entercommand => $X, $Y, 0)
    }
   delete $info->{site};
  }
 my $data = pack('LLLLL',$id,$sflags,$sxy,$swh,$action);
 $t->SendClientMessage('XdndStatus',$src,32,$data);
}

sub XdndDrop
{
 my ($t,$sites) = @_;
 my $event = $t->XEvent;
 my ($src,$flags,$time,$res1,$res2) = unpack('LLLLL',$event->A);
 my $info   = $t->{"XDND$src"};
 my $sflags = 0;
 my $action = 0;
 if ($info)
  {
   $info->{t} = $time;
   my $site = $info->{'site'};
   if ($site)
    {
     my $X = $info->{'X'};
     my $Y = $info->{'Y'};
     $action = $info->{action};
     $site->Apply(-dropcommand => $X, $Y, 'XdndSelection',$action,$info->{types});
     $site->Apply(-entercommand => $X, $Y, 0);
    }
  }
 my ($id) = $t->wrapper;
 my $data  = pack('LLLLL',$id,$sflags,$action,0,0);
 $t->SendClientMessage('XdndFinished',$src,32,$data);
}

sub NoteSites
{my ($class,$t,$sites) = @_;
 my ($wrapper) = $t->wrapper;
 if (@$sites)
  {
   $t->BindClientMessage('XdndLeave',[\&XdndLeave,$sites]);
   $t->BindClientMessage('XdndEnter',[\&XdndEnter,$sites]);
   $t->BindClientMessage('XdndPosition',[\&XdndPosition,$sites]);
   $t->BindClientMessage('XdndDrop',[\&XdndDrop,$sites]);
   $t->property('set','XdndAware','ATOM',32,[XDND_PROTOCOL_VERSION],$wrapper);
  }
 else
  {
   $t->property('delete','XdndAware',$wrapper);
  }
}

1;
__END__
