home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Editores / Perl5 / perl / lib / site / Tk.pm < prev    next >
Encoding:
Perl POD Document  |  1997-08-10  |  12.4 KB  |  574 lines

  1. #
  2. # Copyright (c) 1992-1994 The Regents of the University of California.
  3. # Copyright (c) 1994 Sun Microsystems, Inc.
  4. # Copyright (c) 1995-1997 Nick Ing-Simmons. All rights reserved.
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the same terms as Perl itself, subject 
  7. # to additional disclaimer in Tk/license.terms due to partial
  8. # derivation from Tk4.0 sources.
  9. #
  10. package Tk;
  11. require 5.004;
  12. use     AutoLoader qw(AUTOLOAD);
  13. use     DynaLoader;
  14. require Exporter;
  15. @Tk::ISA = qw(Exporter DynaLoader);
  16.  
  17.  
  18. @EXPORT    = qw(Exists Ev after exit MainLoop DoOneEvent tkinit);
  19. @EXPORT_OK = qw(NoOp *widget *event lsearch catch 
  20.                 DONT_WAIT WINDOW_EVENTS  FILE_EVENTS TIMER_EVENTS 
  21.                 IDLE_EVENTS ALL_EVENTS 
  22.                 NORMAL_BG ACTIVE_BG SELECT_BG 
  23.                 SELECT_FG TROUGH INDICATOR DISABLED BLACK WHITE);
  24. %EXPORT_TAGS = (eventtypes => [qw(DONT_WAIT WINDOW_EVENTS  FILE_EVENTS 
  25.                                   TIMER_EVENTS IDLE_EVENTS ALL_EVENTS)], 
  26.                 variables  => [qw(*widget *event)],
  27.                 colors     => [qw(NORMAL_BG ACTIVE_BG SELECT_BG SELECT_FG 
  28.                                   TROUGH INDICATOR DISABLED BLACK WHITE)],
  29.                );
  30.  
  31. use strict;
  32. use Symbol ();
  33.  
  34. use Carp;
  35.  
  36. # $tk_version and $tk_patchLevel are reset by pTk when a mainwindow
  37. # is created, $VERSION is checked by bootstrap
  38. $Tk::version     = "4.2";
  39. $Tk::patchLevel  = "4.2";
  40. $Tk::VERSION     = '402.002';
  41. $Tk::strictMotif = 0;
  42.                                    
  43. {($Tk::library) = __FILE__ =~ /^(.*)\.pm$/;}
  44. $Tk::library = Tk->findINC('.') unless (-d $Tk::library);
  45.  
  46. $Tk::widget  = undef;
  47. $Tk::event   = undef;
  48.  
  49. # Supress used once warnings on function table pointers 
  50. # How can we do this in the C code?
  51. use vars qw($TkVtab $TkintVtab $LangVtab $TkglueVtab $XlibVtab $TkoptionVtab);  
  52. use vars qw($TixVtab $TixintVtab $TiximgxpmVtab);
  53.  
  54. bootstrap Tk $Tk::VERSION;
  55.  
  56. {
  57.  no strict 'refs';
  58.  *{'exit'} = \&Exit;
  59. }
  60. my $boot_time = timeofday();
  61.  
  62. # This is a workround for Solaris X11 locale handling 
  63. Preload(DynaLoader::dl_findfile('-L/usr/openwin/lib','-lX11')) if (&NeedPreload && -d '/usr/openwin/lib');
  64.  
  65. use Tk::Submethods ('option'    =>  [qw(add get clear readfile)],
  66.                     'clipboard' =>  [qw(clear append)]
  67.                    );
  68.  
  69. sub BackTrace
  70. {
  71.  my $w = shift;
  72.  return unless (@_ || $@);
  73.  my $mess = (@_) ? shift : "$@";
  74.  my $i = 0;  
  75.  my ($pack,$file,$line,$sub) = caller($i++);
  76.  while (1)   
  77.   {          
  78.    my $loc = "at $file line $line";
  79.    ($pack,$file,$line,$sub) = caller($i++);
  80.    last if (!defined($sub) || $sub eq '(eval)');
  81.    $w->AddErrorInfo("$sub $loc");
  82.   }          
  83.  die "$mess\n";
  84. }
  85.  
  86. sub NoOp  { }
  87.  
  88. sub Ev
  89. {
  90.  my @args = @_;
  91.  my $obj;
  92.  if (@args == 1)
  93.   {
  94.    my $arg = pop(@args);
  95.    $obj = (ref $arg) ? $arg : \$arg;
  96.   }
  97.  else 
  98.   {
  99.    $obj = \@args;
  100.   }
  101.  return bless $obj,"Tk::Ev";
  102. }
  103.  
  104. sub InitClass
  105. {
  106.  my ($package,$parent) = @_;
  107.  croak "Unexpected type of parent $parent" unless(ref $parent);
  108.  croak "$parent is not a widget" unless($parent->IsWidget);
  109.  my $mw = $parent->MainWindow;
  110.  unless (exists $mw->{'_ClassInit_'}{$package})
  111.   {
  112.    $package->Install($mw);
  113.    $mw->{'_ClassInit_'}{$package} = $package->ClassInit($mw);
  114.   }
  115. }
  116.  
  117. require Tk::Widget;
  118. require Tk::Image;
  119. require Tk::MainWindow;
  120.  
  121. sub Exists
  122. {my $w = shift;
  123.  return defined($w) && ref($w) && $w->IsWidget && $w->exists;
  124. }
  125.  
  126. sub Time_So_Far
  127. {
  128.  return timeofday() - $boot_time;
  129.  
  130. # Selection* are not autoloaded as names are too long.
  131.  
  132. sub SelectionOwn
  133. {my $widget = shift;
  134.  selection('own',(@_,$widget));
  135. }
  136.  
  137. sub SelectionOwner
  138. {
  139.  selection('own',"-displayof",@_);
  140. }
  141.  
  142. sub SelectionClear
  143. {
  144.  selection('clear',"-displayof",@_);
  145. }
  146.  
  147. sub SelectionExists
  148. {
  149.  selection('exists',"-displayof",@_);
  150. }
  151.  
  152. sub SelectionHandle
  153. {my $widget = shift;
  154.  my $command = pop;
  155.  selection('handle',@_,$widget,$command);
  156. }
  157.  
  158. #
  159. # This is a $SIG{__DIE__} handler which does not change the $@
  160. # string in the way 'croak' does, but rather add to Tk's ErrorInfo.
  161. # It stops at 1st enclosing eval on assumption that the eval
  162. # is part of Tk call process and will add its own context to ErrorInfo
  163. # and then pass on the error.
  164. sub __DIE__
  165. {
  166.  my $mess = shift;
  167.  my $w = $Tk::widget;
  168.  if (defined $w)
  169.   {
  170.    my $i = 0;  
  171.    my ($pack,$file,$line,$sub) = caller($i++);
  172.    while (1)   
  173.     {          
  174.      my $loc = "at $file line $line";
  175.      ($pack,$file,$line,$sub) = caller($i++);
  176.      last if (!defined($sub) || $sub eq '(eval)');
  177.      $w->AddErrorInfo("$sub $loc");
  178.     }          
  179.   }
  180. }
  181.  
  182. sub fileevent
  183. {
  184.  require Tk::IO;
  185.  my ($obj,$file,$mode,$cb) = @_;
  186.  croak "Unknown mode '$mode'" unless $mode =~ /^(readable|writeable)$/;
  187.  unless (ref $file)
  188.   {
  189.    require IO::Handle;
  190.    no strict 'refs';
  191.    $file = Symbol::qualify($file,(caller)[0]);
  192.    $file = bless \*{$file},'IO::Handle';
  193.   }
  194.  if ($cb)
  195.   {
  196.    # Adding the handler
  197.    $cb = Tk::Callback->new($cb);
  198.    if ($mode eq 'readable')
  199.     {
  200.      Tk::IO::CreateReadHandler($file,$cb);
  201.     }
  202.    else
  203.     {
  204.      Tk::IO::CreateWriteHandler($file,$cb);
  205.     }
  206.   }
  207.  else
  208.   {
  209.    if ($mode eq 'readable')
  210.     {
  211.      Tk::IO::DeleteReadHandler($file);
  212.     }
  213.    else
  214.     {
  215.      Tk::IO::DeleteWriteHandler($file);
  216.     }
  217.   }
  218. }
  219.  
  220. sub SplitString
  221. {
  222.  local $_ = shift;
  223.  carp "SplitString '$_'";
  224.  my (@arr, $tmp);
  225.  while (/\{([^{}]*)\}|((?:[^\s\\]|\\.)+)/gs) {
  226.    if (defined $1) { push @arr, $1 }
  227.    else { $tmp = $2 ; $tmp =~ s/\\([\s\\])/$1/g; push @arr, $tmp }
  228.  }
  229.  return @arr;
  230.  #return split(/\s+/,$_);
  231. }
  232.  
  233.  
  234. 1;
  235.  
  236. __END__
  237. # provide an exit() to be exported if exit occurs 
  238. # before a MainWindow->new()
  239. sub exit { CORE::exit(@_);}
  240.  
  241. sub Exists
  242. {my $w = shift;
  243.  return defined($w) && ref($w) && $w->IsWidget && $w->exists;
  244. }
  245.  
  246. sub Error
  247. {my $w = shift;
  248.  my $error = shift;
  249.  if (Exists($w))
  250.   {
  251.    my $grab = $w->grab('current');  
  252.    $grab->Unbusy if (defined $grab);
  253.   }
  254.  chomp($error);
  255.  warn "Tk::Error: $error\n " . join("\n ",@_);
  256. }
  257.  
  258. sub tkinit
  259. {
  260.  return MainWindow->new(@_);
  261. }
  262.  
  263. sub CancelRepeat
  264. {
  265.  my $w = shift->MainWindow;
  266.  my $id = delete $w->{_afterId_};
  267.  $w->after('cancel',$id) if (defined $id);
  268. }
  269.  
  270. sub RepeatId
  271. {
  272.  my ($w,$id) = @_;
  273.  $w = $w->MainWindow;
  274.  $w->CancelRepeat;
  275.  $w->{_afterId_} = $id;
  276. }
  277.  
  278.  
  279.  
  280. #----------------------------------------------------------------------------
  281. # focus.tcl --
  282. #
  283. # This file defines several procedures for managing the input
  284. # focus.
  285. #
  286. # @(#) focus.tcl 1.6 94/12/19 17:06:46
  287. #
  288. # Copyright (c) 1994 Sun Microsystems, Inc.
  289. #
  290. # See the file "license.terms" for information on usage and redistribution
  291. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  292.  
  293. sub FocusChildren { shift->children }
  294.  
  295. #
  296. # focusNext --
  297. # This procedure is invoked to move the input focus to the next window
  298. # after a given one. "Next" is defined in terms of the window
  299. # stacking order, with all the windows underneath a given top-level
  300. # (no matter how deeply nested in the hierarchy) considered except
  301. # for frames and toplevels.
  302. #
  303. # Arguments:
  304. # w - Name of a window: the procedure will set the focus
  305. # to the next window after this one in the traversal
  306. # order.
  307. sub focusNext
  308. {
  309.  my $w = shift;
  310.  my $cur = $w;
  311.  while (1)
  312.   {
  313.    # Descend to just before the first child of the current widget.
  314.    my $parent = $cur;
  315.    my @children = $cur->FocusChildren();
  316.    my $i = -1;
  317.    # Look for the next sibling that isn't a top-level.
  318.    while (1)
  319.     {
  320.      $i += 1;
  321.      if ($i < @children)
  322.       {
  323.        $cur = $children[$i];
  324.        next if ($cur->toplevel == $cur);
  325.        last
  326.       }
  327.      # No more siblings, so go to the current widget's parent.
  328.      # If it's a top-level, break out of the loop, otherwise
  329.      # look for its next sibling.
  330.      $cur = $parent;
  331.      last if ($cur->toplevel() == $cur);
  332.      $parent = $parent->parent();
  333.      @children = $parent->FocusChildren();
  334.      $i = lsearch(\@children,$cur);
  335.     }
  336.    if ($cur == $w || $cur->FocusOK)
  337.     {
  338.      $cur->Tk::focus;
  339.      return;
  340.     }
  341.   }
  342. }
  343. # focusPrev --
  344. # This procedure is invoked to move the input focus to the previous
  345. # window before a given one. "Previous" is defined in terms of the
  346. # window stacking order, with all the windows underneath a given
  347. # top-level (no matter how deeply nested in the hierarchy) considered.
  348. #
  349. # Arguments:
  350. # w - Name of a window: the procedure will set the focus
  351. # to the previous window before this one in the traversal
  352. # order.
  353. sub focusPrev
  354. {
  355.  my $w = shift;
  356.  my $cur = $w;
  357.  my @children;
  358.  my $i;
  359.  my $parent;
  360.  while (1)
  361.   {
  362.    # Collect information about the current window's position
  363.    # among its siblings. Also, if the window is a top-level,
  364.    # then reposition to just after the last child of the window.
  365.    if ($cur->toplevel() == $cur)
  366.     {
  367.      $parent = $cur;
  368.      @children = $cur->FocusChildren();
  369.      $i = @children;
  370.     }
  371.    else
  372.     {
  373.      $parent = $cur->parent();
  374.      @children = $parent->FocusChildren();
  375.      $i = lsearch(\@children,$cur);
  376.     }
  377.    # Go to the previous sibling, then descend to its last descendant
  378.    # (highest in stacking order. While doing this, ignore top-levels
  379.    # and their descendants. When we run out of descendants, go up
  380.    # one level to the parent.
  381.    while ($i > 0)
  382.     {
  383.      $i--;
  384.      $cur = $children[$i];
  385.      next if ($cur->toplevel() == $cur);
  386.      $parent = $cur;
  387.      @children = $parent->FocusChildren();
  388.      $i = @children;
  389.     }
  390.    $cur = $parent;
  391.    if ($cur == $w || $cur->FocusOK)
  392.     {
  393.      $cur->Tk::focus;
  394.      return;
  395.     }
  396.   }
  397.  
  398. }
  399.  
  400. sub FocusOK
  401. {
  402.  my $w = shift;
  403.  my $value;
  404.  catch { $value = $w->cget('-takefocus') };
  405.  if (!$@ && defined($value))
  406.   {
  407.    return 0 if ($value eq '0');
  408.    return 1 if ($value eq '1');
  409.    $value = $w->$value();
  410.    return $value if (defined $value);
  411.   }
  412.  if (!$w->viewable)
  413.   {
  414.    return 0;
  415.   }
  416.  catch { $value = $w->cget('-state') } ;
  417.  if (!$@ && defined($value) && $value eq "disabled")
  418.   {
  419.    return 0;
  420.   }
  421.  $value = grep(/Key|Focus/,$w->Tk::bind(),$w->Tk::bind(ref($w)));
  422.  return $value;
  423. }
  424.  
  425.  
  426. # focusFollowsMouse
  427. #
  428. # If this procedure is invoked, Tk will enter "focus-follows-mouse"
  429. # mode, where the focus is always on whatever window contains the
  430. # mouse. If this procedure isn't invoked, then the user typically
  431. # has to click on a window to give it the focus.
  432. #
  433. # Arguments:
  434. # None.
  435.  
  436. sub EnterFocus
  437. {
  438.  my $w  = shift;
  439.  my $Ev = $w->XEvent;
  440.  my $d  = $Ev->d;
  441.  $w->Tk::focus() if ($d eq "NotifyAncestor" ||  $d eq "NotifyNonlinear" ||  $d eq "NotifyInferior");
  442. }
  443.  
  444. sub focusFollowsMouse
  445. {
  446.  my $widget = shift;
  447.  $widget->bind('all',"EnterFocus");
  448. }
  449.  
  450. # tkTraverseToMenu --
  451. # This procedure implements keyboard traversal of menus. Given an
  452. # ASCII character "char", it looks for a menubutton with that character
  453. # underlined. If one is found, it posts the menubutton's menu
  454. #
  455. # Arguments:
  456. # w - Window in which the key was typed (selects
  457. # a toplevel window).
  458. # char - Character that selects a menu. The case
  459. # is ignored. If an empty string, nothing
  460. # happens.
  461. sub TraverseToMenu
  462. {
  463.  my $w = shift;
  464.  my $char = shift;
  465.  return unless(defined $char && $char ne "");
  466.  $w = $w->toplevel->FindMenu($char);
  467.  $w->PostFirst() if (defined $w);
  468. }
  469. # tkFirstMenu --
  470. # This procedure traverses to the first menubutton in the toplevel
  471. # for a given window, and posts that menubutton's menu.
  472. #
  473. # Arguments:
  474. # w - Name of a window. Selects which toplevel
  475. # to search for menubuttons.
  476. sub FirstMenu
  477. {
  478.  my $w = shift;
  479.  $w = $w->toplevel->FindMenu("");
  480.  $w->PostFirst() if (defined $w);
  481. }
  482.  
  483. # These wrappers don't use method syntax so need to live
  484. # in same package as raw Tk routines are newXS'ed into.
  485.  
  486. sub Selection
  487. {my $widget = shift;
  488.  my $cmd    = shift;
  489.  croak "Use SelectionOwn/SelectionOwner" if ($cmd eq 'own');
  490.  croak "Use Selection\u$cmd()";
  491. }
  492.  
  493. sub Clipboard
  494. {my $w = shift;
  495.  my $cmd    = shift;
  496.  croak "Use clipboard\u$cmd()";
  497. }
  498.  
  499. sub Receive
  500. {
  501.  my $w = shift;
  502.  warn "Receive(" . join(',',@_) .")";
  503.  die "Tk rejects send(" . join(',',@_) .")\n";
  504. }
  505.  
  506. sub break
  507. {
  508.  die "_TK_BREAK_\n";
  509. }
  510.  
  511. sub idletasks
  512. {
  513.  shift->update('idletasks');
  514. }
  515.  
  516. sub updateWidgets
  517. {
  518.  my ($w) = @_;
  519.  while ($w->DoOneEvent(DONT_WAIT|IDLE_EVENTS|WINDOW_EVENTS))
  520.   {
  521.   }
  522.  $w;
  523. }
  524.  
  525. sub ImageNames
  526. {
  527.  image('names');
  528. }
  529.  
  530. sub ImageTypes
  531. {
  532.  image('types');
  533. }
  534.  
  535. sub interps
  536. {
  537.  my $w = shift;
  538.  return $w->winfo('interps','-displayof');
  539. }
  540.  
  541. sub findINC
  542. {
  543.  my $file = join('/',@_);
  544.  my $dir;
  545.  $file  =~ s,::,/,g;
  546.  foreach $dir (@INC)
  547.   {
  548.    my $path;
  549.    return $path if (-e ($path = "$dir/$file"));
  550.   }
  551.  return undef;
  552. }
  553.  
  554. sub lsearch
  555. {my $ar = shift;
  556.  my $x  = shift;
  557.  my $i;
  558.  for ($i = 0; $i < scalar @$ar; $i++)
  559.   {
  560.    return $i if ($$ar[$i] eq $x);
  561.   }
  562.  return -1;
  563. }
  564.  
  565. # a wrapper on eval which turns off user $SIG{__DIE__}
  566. sub catch (&)
  567. {
  568.  my $sub = shift;
  569.  eval {local $SIG{'__DIE__'}; &$sub };
  570. }
  571.  
  572.