# -*- perl -*-

#
# $Id: TkChange.pm,v 1.10 2003/01/08 21:01:16 eserte Exp $
# Author: Slaven Rezic
#
# Copyright (C) 1999 Slaven Rezic. All rights reserved.
# This package is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Mail: eserte@cs.tu-berlin.de
# WWW:  http://user.cs.tu-berlin.de/~eserte/
#

package TkChange;

# Override von Standard-Methoden aus Tk.

# Verhindert, daß neue Fenster außerhalb des Fensters gezeichnet werden.
# Leider wird die Rahmenbreite der Window-Manager-Dekoration ignoriert.
package Tk::Wm; # AUTOLOAD: ignore

# XXX for window manager frame
use vars qw($wm_border_x $wm_border_y);
$wm_border_x = 6;
$wm_border_y = 28;

# XXX width/height-problem mit wine
# XXX aber ohne gehen popup-menüs anscheinend nicht...
sub XXXPopup
{
 my $w = shift;
 $w->withdraw;
 $w->positionfrom('user');
 if (defined $main::os and $main::os eq 'win') {
  my(%args) = @_;
  # don't use this on Win32 because of clicktofocus...
  delete $args{-popover} if $args{-popover} eq 'cursor';
  $w->configure(%args);
 } else {
  $w->configure(@_) if @_;
 }
# $w->idletasks;
 my($mw,$mh);
# if (defined $main::x11 && $Tk::VERSION >= 800) { # for wrapper
#     my $wrp = ($w->toplevel->wrapper)[0];
#     $w->update;
#     my %res = $main::x11->GetGeometry($wrp);
#     ($mw,$mh) = ($res{'width'}, $res{'height'});
# } else {
     ($mw,$mh) = ($w->reqwidth,$w->reqheight);
     $mw += $wm_border_x; $mh += $wm_border_y;
#warn "width=$mw height=$mh";
# }
 my ($rx,$ry,$rw,$rh) = (0,0,0,0);
 my $base    = $w->cget('-popover');
 my $outside = 0;
 if (defined $base)
  {
   if ($base eq 'cursor')
    {
     ($rx,$ry) = $w->pointerxy;
    }
   else
    {
     $rx = $base->rootx; 
     $ry = $base->rooty; 
     $rw = $base->Width; 
     $rh = $base->Height;
    }
  }
 else
  {
   my $sc = ($w->parent) ? $w->parent->toplevel : $w;
   $rx = -$sc->vrootx;
   $ry = -$sc->vrooty;
   $rw = $w->screenwidth;
   $rh = $w->screenheight;
  }
 my ($X,$Y) = AnchorAdjust($w->cget('-overanchor'),$rx,$ry,$rw,$rh);
 ($X,$Y)    = AnchorAdjust($w->cget('-popanchor'),$X,$Y,-$mw,-$mh);

 my ($sh,$sw) = ($w->screenheight, $w->screenwidth);
 if ($X + $mw > $sw) { $X = $sw - $mw }
 if ($X < 0)         { $X = 0         }
 if ($Y + $mh > $sh) { $Y = $sh - $mh }
 if ($Y < 0)         { $Y = 0         }

 ($X,$Y) = (int($X), int($Y));
 if ($X < $wm_border_x) { $X = $wm_border_x }
 if ($Y < $wm_border_y) { $Y = $wm_border_y }
 $w->deiconify;
# $w->Post($X,$Y);
 $w->positionfrom('user');
 $w->geometry("+$X+$Y");
#warn "+$X+$Y";
#warn $w->geometry;
## to prevent KDE slowness:
# $w->raise;
}

#  ######################################################################
#  #
#  # Beim Browsen mit den Cursortasten wechselt der aktive Eintrag automatisch
#  # in ein Cascade. Nervig.
#  # Aber: Mit Tk402 geht das hier nicht, auch wenn ich kurz davor ein
#  #       "return 1" mache.

#  package Tk::Menu;
#  use Tk::Menu;

#  sub FirstEntry
#  {
#   my $menu = shift;
#   return if (!defined($menu) || $menu eq '' || !ref($menu));
#   $menu->SetFocus;
#   return if ($menu->index('active') ne 'none');
#   my $last = $menu->index('last');
#   return if ($last eq 'none');
#   for (my $i = 0;$i <= $last;$i += 1)
#    {
#     my $state = eval {local $SIG{__DIE__};  $menu->entrycget($i,'-state') };
#     if (defined $state && $state ne 'disabled' && !$menu->typeIS($i,'tearoff'))
#      {
#       $menu->activate($i);
#       $menu->GenerateMenuSelect;
#  #      if ($menu->type($i) eq 'cascade')
#  #       {
#  #        my $cascade = $menu->entrycget($i,'-menu');
#  #        if (defined $cascade)
#  #         {
#  #          $menu->postcascade($i);
#  #          $cascade->FirstEntry;
#  #         }
#  #       }
#       return;
#      }
#    }
#  }

#  sub NextMenu
#  {
#   my $menu = shift;
#   my $direction = shift;
#   # First handle traversals into and out of cascaded menus.
#   my $count;
#   if ($direction eq 'right')
#    {
#  #XXX Problem: ein weiteres "right" wird nicht mehr ausgeführt
#  warn "right";
#     $count = 1;
#     if ($menu->typeIS('active','cascade'))
#      {
#  warn "1 $menu";
#  warn ">>" . $menu->index("active");
#       $menu->postcascade('active');
#       my $m2 = $menu->entrycget('active','-menu');
#  warn $m2;
#       $m2->FirstEntry if (defined $m2);
#       return;
#      }
#     else
#      {
#  warn 2;
#       my $parent = $menu->parent;
#       while ($parent->PathName ne '.')
#        {
#         if ($parent->IsMenu && $parent->cget('-type') eq 'menubar')
#          {
#           $parent->SetFocus;
#           $parent->NextEntry(1);
#           return;
#          }
#         $parent = $parent->parent;
#        }
#      }
#    }
#   else
#    {
#     $count = -1;
#     my $m2 = $menu->parent;
#     if ($m2->IsMenu)
#      {
#       if ($m2->cget('-type') ne 'menubar')
#        {
#         $menu->activate('none');
#         $menu->GenerateMenuSelect;
#         $menu->unpost;
#         $m2->SetFocus;
#         # This code unposts any posted submenu in the parent. XXX
#  #       my $tmp = $m2->index('active');
#  #       $m2->activate('none');
#  #       $m2->activate($tmp);
#         return;
#        }
#      }
#    }
#   # Can't traverse into or out of a cascaded menu. Go to the next
#   # or previous menubutton, if that makes sense.

#   my $m2 = $menu->parent;
#   if ($m2->IsMenu)
#    {
#     if ($m2->cget('-type') eq 'menubar')
#      {
#       $m2->SetFocus;
#       $m2->NextEntry(-1);
#       return;
#      }
#    }

#   my $w = $Tk::postedMb;
#   return unless defined $w;
#   my @buttons = $w->parent->children;
#   my $length = @buttons;
#   my $i = Tk::lsearch(\@buttons,$w)+$count;
#   my $mb;
#   while (1)
#    {
#     while ($i < 0)
#      {
#       $i += $length
#      }
#     while ($i >= $length)
#      {
#       $i += -$length
#      }
#     $mb = $buttons[$i];
#     last if ($mb->IsMenubutton && $mb->cget('-state') ne 'disabled'
#              && defined($mb->cget('-menu'))
#              && $mb->cget('-menu')->index('last') ne 'none'
#             );
#     return if ($mb == $w);
#     $i += $count
#    }
#   $mb->PostFirst();
#  }

### Was war das hier? Eine noch ältere Version?

# sub NextEntry
# {
#  my $menu = shift;
#  my $count = shift;
#  if ($menu->index('last') eq 'none')
#   {
#    return;
#   }
#  my $length = $menu->index('last')+1;
#  my $quitAfter = $length;
#  my $active = $menu->index('active');
#  my $i = ($active eq 'none') ? 0 : $active+$count;
#  while (1)
#   {
#    return if ($quitAfter <= 0);
#    while ($i < 0)
#     {
#      $i += $length
#     }
#    while ($i >= $length)
#     {
#      $i += -$length
#     }
#    my $state = eval {local $SIG{__DIE__};  $menu->entrycget($i,'-state') };
#    last if (defined($state) && $state ne 'disabled');
#    return if ($i == $active);
#    $i += $count;
#    $quitAfter -= 1;
#   }
#  if (defined $active and $menu->type($active) eq 'cascade')
#   {
# #XXX not perfect --- arrow is still highlighted
#    $menu->entrycget($active, '-menu')->unpost;
#   }
#  $menu->activate($i);
#  $menu->GenerateMenuSelect;
#  if ($menu->type($i) eq 'cascade')
#   {
#    my $cascade = $menu->entrycget($i, '-menu');
#    $menu->postcascade($i);
# #   $cascade->FirstEntry if (defined $cascade);
#   }
# }
######################################################################

package Tk::Widget;

if ($Tk::platform eq 'MSWin32') { # under X11 another Busy implementation is used

local $^W = 0;
eval <<'EOF';
sub BusyRecurse
{
 my ($restore,$w,$cursor,$recurse,$top) = @_;
 my $c = $w->{_Cursor_} || $w->cget('-cursor');
 my @tags = $w->bindtags;
 if ($top || defined($c))
  {
   push(@$restore, sub { $w->configure(-cursor => $c); $w->bindtags(\@tags) });
   $w->configure(-cursor => $cursor);
  }
 else
  {
   push(@$restore, sub { $w->bindtags(\@tags) });
  }
 $w->bindtags(['Busy',@tags]);
 if ($recurse)
  {
   foreach my $child ($w->children)
    {
     BusyRecurse($restore,$child,$cursor,1,0);
    }
  }
 return $restore;
}
EOF
die $@ if $@;
}

1;

__END__
