home *** CD-ROM | disk | FTP | other *** search
/ CLIX - Fazer Clix Custa Nix / CLIX-CD.cdr / mac / lib / Mac / Windows.pm < prev    next >
Text File  |  1998-04-06  |  21KB  |  1,017 lines

  1. =head1 NAME
  2.  
  3. Mac::Windows - Macintosh Toolbox Interface to Window Manager
  4.  
  5. =head1 SYNOPSIS
  6.  
  7. =head1 DESCRIPTION
  8.  
  9. Access to Inside Macintosh is essential for proper use of these functions.
  10. Explanations of terms, processes and procedures are provided there.
  11. Any attempt to use these functions without guidance can cause severe errors in 
  12. your machine, including corruption of data. B<You have been warned.>
  13.  
  14. =cut
  15.     
  16. use strict;
  17.  
  18. package Mac::Windows;
  19.  
  20. BEGIN {
  21.     use Exporter   ();
  22.     use DynaLoader ();
  23.     
  24.     use vars qw(@ISA @EXPORT @EXPORT_OK);
  25.     
  26.     @ISA = qw(Exporter DynaLoader);
  27.     @EXPORT = qw(
  28.         GetGrayRgn
  29.         GetWMgrPort
  30.         NewWindow
  31.         GetNewWindow
  32.         DisposeWindow
  33.         GetWTitle
  34.         SelectWindow
  35.         HideWindow
  36.         ShowWindow
  37.         ShowHide
  38.         HiliteWindow
  39.         BringToFront
  40.         SendBehind
  41.         FrontWindow
  42.         DrawGrowIcon
  43.         MoveWindow
  44.         SizeWindow
  45.         ZoomWindow
  46.         InvalRect
  47.         InvalRgn
  48.         ValidRect
  49.         ValidRgn
  50.         BeginUpdate
  51.         EndUpdate
  52.         SetWRefCon
  53.         GetWRefCon
  54.         SetWindowPic
  55.         GetWindowPic
  56.         GrowWindow
  57.         FindWindow
  58.         PinRect
  59.         DragGrayRgn
  60.         TrackBox
  61.         GetCWMgrPort
  62.         SetDeskCPat
  63.         NewCWindow
  64.         GetNewCWindow
  65.         GetWVariant
  66.         SetWTitle
  67.         TrackGoAway
  68.         DragWindow
  69.         GetWindowKind
  70.         SetWindowKind
  71.         IsWindowVisible
  72.         IsWindowHilited
  73.         GetWindowGoAwayFlag
  74.         GetWindowZoomFlag
  75.         GetWindowStructureRgn
  76.         GetWindowContentRgn
  77.         GetWindowUpdateRgn
  78.         GetWindowTitleWidth
  79.         GetNextWindow
  80.         GetWindowStandardState
  81.         SetWindowStandardState
  82.         GetWindowUserState
  83.         SetWindowUserState
  84.     
  85.         kWindowDefProcType
  86.         kStandardWindowDefinition
  87.         kRoundWindowDefinition
  88.         kFloatingWindowDefinition
  89.         kModalDialogVariantCode
  90.         kMovableModalDialogVariantCode
  91.         kSideFloaterVariantCode
  92.         documentProc
  93.         dBoxProc
  94.         plainDBox
  95.         altDBoxProc
  96.         noGrowDocProc
  97.         movableDBoxProc
  98.         zoomDocProc
  99.         zoomNoGrow
  100.         rDocProc
  101.         floatProc
  102.         floatGrowProc
  103.         floatZoomProc
  104.         floatZoomGrowProc
  105.         floatSideProc
  106.         floatSideGrowProc
  107.         floatSideZoomProc
  108.         floatSideZoomGrowProc
  109.         kDialogWindowKind
  110.         kApplicationWindowKind
  111.         inDesk
  112.         inMenuBar
  113.         inSysWindow
  114.         inContent
  115.         inDrag
  116.         inGrow
  117.         inGoAway
  118.         inZoomIn
  119.         inZoomOut
  120.         wDraw
  121.         wHit
  122.         wCalcRgns
  123.         wNew
  124.         wDispose
  125.         wGrow
  126.         wDrawGIcon
  127.         deskPatID
  128.         wNoHit
  129.         wInContent
  130.         wInDrag
  131.         wInGrow
  132.         wInGoAway
  133.         wInZoomIn
  134.         wInZoomOut
  135.         wContentColor
  136.         wFrameColor
  137.         wTextColor
  138.         wHiliteColor
  139.         wTitleBarColor
  140.     );
  141.     
  142.     @EXPORT_OK = qw(
  143.         %Window
  144.     );
  145. }
  146.  
  147. =head2 Constants
  148.  
  149. =over 4
  150.  
  151. =item kWindowDefProcType
  152.  
  153. =item kStandardWindowDefinition
  154.  
  155. =item kRoundWindowDefinition
  156.  
  157. =item kFloatingWindowDefinition
  158.  
  159. =item kModalDialogVariantCode
  160.  
  161. =item kMovableModalDialogVariantCode
  162.  
  163. =item kSideFloaterVariantCode
  164.  
  165. =item documentProc
  166.  
  167. =item dBoxProc
  168.  
  169. =item plainDBox
  170.  
  171. =item altDBoxProc
  172.  
  173. =item noGrowDocProc
  174.  
  175. =item movableDBoxProc
  176.  
  177. =item zoomDocProc
  178.  
  179. =item zoomNoGrow
  180.  
  181. =item rDocProc
  182.  
  183. =item floatProc
  184.  
  185. =item floatGrowProc
  186.  
  187. =item floatZoomProc
  188.  
  189. =item floatZoomGrowProc
  190.  
  191. =item floatSideProc
  192.  
  193. =item floatSideGrowProc
  194.  
  195. =item floatSideZoomProc
  196.  
  197. =item floatSideZoomGrowProc
  198.  
  199. Window definition procedure IDs.
  200.  
  201. =cut
  202. sub kWindowDefProcType ()          {     'WDEF'; }
  203. sub kStandardWindowDefinition ()   {          0; }
  204. sub kRoundWindowDefinition ()      {          1; }
  205. sub kFloatingWindowDefinition ()   {        124; }
  206. sub kModalDialogVariantCode ()     {          1; }
  207. sub kMovableModalDialogVariantCode () {       5; }
  208. sub kSideFloaterVariantCode ()     {          8; }
  209. sub documentProc ()                {          0; }
  210. sub dBoxProc ()                    {          1; }
  211. sub plainDBox ()                   {          2; }
  212. sub altDBoxProc ()                 {          3; }
  213. sub noGrowDocProc ()               {          4; }
  214. sub movableDBoxProc ()             {          5; }
  215. sub zoomDocProc ()                 {          8; }
  216. sub zoomNoGrow ()                  {         12; }
  217. sub rDocProc ()                    {         16; }
  218. sub floatProc ()                   {       1985; }
  219. sub floatGrowProc ()               {       1987; }
  220. sub floatZoomProc ()               {       1989; }
  221. sub floatZoomGrowProc ()           {       1991; }
  222. sub floatSideProc ()               {       1993; }
  223. sub floatSideGrowProc ()           {       1995; }
  224. sub floatSideZoomProc ()           {       1997; }
  225. sub floatSideZoomGrowProc ()       {       1999; }
  226.  
  227.  
  228. =item kDialogWindowKind
  229.  
  230. =item kApplicationWindowKind
  231.  
  232. Predefined window kinds.
  233.  
  234. =cut
  235. sub kDialogWindowKind ()           {          2; }
  236. sub kApplicationWindowKind ()      {          8; }
  237.  
  238.  
  239. =item inDesk
  240.  
  241. =item inMenuBar
  242.  
  243. =item inSysWindow
  244.  
  245. =item inContent
  246.  
  247. =item inDrag
  248.  
  249. =item inGrow
  250.  
  251. =item inGoAway
  252.  
  253. =item inZoomIn
  254.  
  255. =item inZoomOut
  256.  
  257. Part codes for C<FindWindow>.
  258.  
  259. =cut
  260. sub inDesk ()                      {          0; }
  261. sub inMenuBar ()                   {          1; }
  262. sub inSysWindow ()                 {          2; }
  263. sub inContent ()                   {          3; }
  264. sub inDrag ()                      {          4; }
  265. sub inGrow ()                      {          5; }
  266. sub inGoAway ()                    {          6; }
  267. sub inZoomIn ()                    {          7; }
  268. sub inZoomOut ()                   {          8; }
  269.  
  270.  
  271. =item wDraw
  272.  
  273. =item wHit
  274.  
  275. =item wCalcRgns
  276.  
  277. =item wNew
  278.  
  279. =item wDispose
  280.  
  281. =item wGrow
  282.  
  283. =item wDrawGIcon
  284.  
  285. =item deskPatID
  286.  
  287. Part codes for the draw message to the window definition procedure.
  288.  
  289. =cut
  290. sub wDraw ()                       {          0; }
  291. sub wHit ()                        {          1; }
  292. sub wCalcRgns ()                   {          2; }
  293. sub wNew ()                        {          3; }
  294. sub wDispose ()                    {          4; }
  295. sub wGrow ()                       {          5; }
  296. sub wDrawGIcon ()                  {          6; }
  297. sub deskPatID ()                   {         16; }
  298.  
  299.  
  300. =item wNoHit
  301.  
  302. =item wInContent
  303.  
  304. =item wInDrag
  305.  
  306. =item wInGrow
  307.  
  308. =item wInGoAway
  309.  
  310. =item wInZoomIn
  311.  
  312. =item wInZoomOut
  313.  
  314. Part codes for the hit message to the window definition procedure.
  315.  
  316. =cut
  317. sub wNoHit ()                      {          0; }
  318. sub wInContent ()                  {          1; }
  319. sub wInDrag ()                     {          2; }
  320. sub wInGrow ()                     {          3; }
  321. sub wInGoAway ()                   {          4; }
  322. sub wInZoomIn ()                   {          5; }
  323. sub wInZoomOut ()                  {          6; }
  324.  
  325.  
  326. =item wContentColor
  327.  
  328. =item wFrameColor
  329.  
  330. =item wTextColor
  331.  
  332. =item wHiliteColor
  333.  
  334. =item wTitleBarColor
  335.  
  336. Colors in window color record.
  337.  
  338. =cut
  339. sub wContentColor ()               {          0; }
  340. sub wFrameColor ()                 {          1; }
  341. sub wTextColor ()                  {          2; }
  342. sub wHiliteColor ()                {          3; }
  343. sub wTitleBarColor ()              {          4; }
  344.  
  345. =back
  346.  
  347. =cut
  348.  
  349. bootstrap Mac::Windows;
  350.  
  351. =include Windows.xs
  352.  
  353. =head2 MacWindow - The Object Interface
  354.  
  355. Correctly handling a Mac window requires quite a bit of event management. The
  356. C<MacWindow> class relieves you of most of these duties. Most of the events
  357. received are dispatched to a set of panes as defined in C<Mac::Pane>.
  358.  
  359. =over 4
  360.  
  361. =cut
  362. package MacWindow;
  363.  
  364. BEGIN {
  365.     use Carp;
  366.     use Mac::Hooks ();
  367.     use Mac::Events;
  368.     use Mac::Events qw($CurrentEvent @Event);
  369.     use Mac::QuickDraw qw(SetPort GlobalToLocal GetClip ClipRect SetClip EraseRect SetCursor);
  370.     import Mac::Windows;
  371.     import Mac::Windows qw(%Window);
  372.  
  373.     use vars qw(@ISA);
  374.     
  375.     @ISA = qw(Mac::Hooks);
  376. }
  377.  
  378. =head2 Creating and Destructing MacWindow objects
  379.  
  380. =item new MacWindow PORT
  381.  
  382. =item new MacWindow ID [, BEHIND]
  383.  
  384. =item new MacWindow BOUNDS, TITLE, VISIBLE, PROC, GOAWAY [, REFCON [, BEHIND]]
  385.  
  386. Register a new window. In the first form, registers an existing window. In the
  387. second form, calls C<GetNewWindow>. In the third form, calls C<NewWindow>.
  388.  
  389. =cut
  390. sub new {
  391.     my($class) = shift @_;
  392.     my($type) = @_;
  393.     my($port);
  394.     
  395.     if (ref($type) eq "Rect") {
  396.         $port = NewWindow(@_) or croak "NewWindow failed";
  397.     } elsif (!ref($type)) {
  398.         $port = GetNewWindow(@_) or croak "GetNewWindow failed";
  399.     } else {
  400.         $port = $type;
  401.     }
  402.     my(%vars) = 
  403.         (port => $port, panes => [], focusable => [], focus => 0, 
  404.          idlealways => [], idlefront => [], tabbing => 1);
  405.     $Window{$$port} = bless \%vars, $class;
  406. }
  407.  
  408. =item dispose 
  409.  
  410. Unregisters and disposes the window.
  411.  
  412. =cut
  413. sub dispose {
  414.     my($self) = @_;
  415.     return unless $self->{port};
  416.     
  417.     for my $pane (@{$self->{panes}}) { 
  418.         $pane->detach($self); 
  419.     };
  420.     defined($_[0]->callhook("dispose", @_)) and return;
  421.     delete $Window{${$self->{port}}};
  422.     DisposeWindow($self->{port});
  423.     $self->{port} = "";
  424. }
  425.  
  426. sub DESTROY {
  427.     my($my) = @_;
  428.     $my->dispose;
  429. }
  430.  
  431. =back 
  432.  
  433. =head2 Accessing Components
  434.  
  435. =over 4
  436.  
  437. =item window
  438.  
  439. Returns the underlying toolbox C<GrafPtr>.
  440.  
  441. =cut
  442. sub window {
  443.     my($my) = @_;
  444.     
  445.     $my->{port};
  446. }
  447.  
  448. =item add_pane PANE
  449.  
  450. Adds a pane to the window.
  451.  
  452. =cut
  453. sub add_pane {
  454.     my($self, $pane) = @_;
  455.     
  456.     unshift @{$self->{panes}}, $pane;
  457.     
  458.     $pane->attach($self);
  459. }
  460.  
  461. =item remove_pane PANE
  462.  
  463. Removes the pane.
  464.  
  465. =cut
  466. sub remove_pane {
  467.     my($self, $pane) = @_;
  468.     
  469.     $self->remove_focusable($pane);
  470.     $self->remove_idle($pane);
  471.     
  472.     my $panes = $self->{panes};
  473.     
  474.     $pane->detach($self);
  475.     
  476.     @$panes = grep { $_ != $pane } @$panes;
  477. }
  478.  
  479. =item add_idle PANE [, FRONT=0]
  480.  
  481. Indicates that the pane needs to get regular time slices. If FRONT is set, the
  482. pane only needs time if its window is active.
  483.  
  484. =cut
  485. sub add_idle {
  486.     my($self, $pane, $front) = @_;
  487.     my $idle = $front ? $self->{idlefront} : $self->{idlealways};
  488.  
  489.     push @$idle, $pane;
  490. }
  491.  
  492. =item remove_idle PANE
  493.  
  494. Indicates that the pane no longer needs idle time.
  495.  
  496. =cut
  497. sub remove_idle {
  498.     my($self, $pane) = @_;
  499.  
  500.     my $idle = $self->{idlealways};
  501.     @$idle = grep { $_ != $pane } @$idle;
  502.  
  503.     $idle = $self->{idlefront};
  504.     @$idle = grep { $_ != $pane } @$idle;   
  505. }
  506.  
  507. =item add_focusable PANE
  508.  
  509. Indicates that a pane can get the focus.
  510.  
  511. =cut
  512. sub add_focusable {
  513.     my($self, $pane) = @_;
  514.     my $focusable = $self->{focusable};
  515.     
  516.     push @$focusable, $pane;
  517.     
  518.     $pane->focus($self, 1) if scalar(@$focusable) == 1;
  519. }
  520.  
  521. =item remove_focusable PANE
  522.  
  523. Indicates that no instance of this pane can get the focus.
  524.  
  525. =cut
  526. sub remove_focusable {
  527.     my($self, $pane) = @_;
  528.     my $focusable = $self->{focusable};
  529.     
  530.     return unless scalar(@$focusable);
  531.     
  532.     my $focus     = ${$focusable}[$self->{focus}];
  533.     my $focused   = $focus == $pane;
  534.     
  535.     $pane->focus($self, 0) if $focused;
  536.     
  537.     @$focusable = grep { $_ != $pane } @$focusable;
  538.     
  539.     if (my $focus_count = scalar(@$focusable)) {
  540.         if ($focused) {
  541.             $self->{focus} %= $focus_count;
  542.             ${$focusable}[$self->{focus}]->focus($self, 1);
  543.         } else {
  544.             if ($self->{focus} >= scalar(@$focusable) 
  545.              || ${$focusable}[$self->{focus}] != $focus
  546.             ) {
  547.                 --$self->{focus};
  548.             }
  549.         }
  550.     } else {
  551.         $self->{focus} = 0;
  552.     }
  553. }
  554.  
  555. =item has_focus PANE
  556.  
  557. Returns whether PANE currently is focused.
  558.  
  559. =cut
  560. sub has_focus {
  561.     my($my, $pane) = @_;
  562.  
  563.     return ${$my->{focusable}}[$my->{focus}] == $pane;
  564. }
  565.  
  566. =item can_focus 
  567.  
  568. Returns whether there are at least 2 focusable panes.
  569.  
  570. =cut
  571. sub can_focus {
  572.     my($my) = @_;
  573.     
  574.     return scalar(@{$my->{focusable}}) > 1;
  575. }
  576.  
  577. =item advance_focus [STEP]
  578.  
  579. =item advance_focus PANE
  580.  
  581. Advance the focus by STEP or to PANE.
  582.  
  583. =cut
  584. sub advance_focus {
  585.     my($my,$step) = @_;
  586.     $step ||= 1;
  587.     my $focusable = $my->{focusable};
  588.     my $max = scalar(@$focusable);
  589.     return if $max < 2;
  590.     my $focus = $my->{focus};
  591.     my $newfocus;
  592.     if (ref($step)) {
  593.         for ($newfocus=0; $newfocus<$max; ++$newfocus) {
  594.             goto switchfocus if $focusable->[$newfocus] == $step;
  595.         }
  596.         return;
  597.     } else {
  598.         $newfocus = ($focus+$max+$step) % $max;
  599.     }
  600. switchfocus:
  601.     return if $newfocus == $focus;
  602.     $my->{focus} = $newfocus;
  603.     $focusable->[$focus]->focus($my, 0);
  604.     $focusable->[$newfocus]->focus($my, 1);
  605. }
  606.  
  607. =back
  608.  
  609. =head2 Event Handling
  610.  
  611. =over 4
  612.  
  613. =item activate ACTIVE, SUSPEND
  614.  
  615. Handle activation of the window, which is already set to the current port.
  616. By default doesn't do anything but update the focus. Override as necessary.
  617.  
  618. The parameters distinguish the four cases:
  619.  
  620.    Event      ACTIVE  SUSPEND
  621.    
  622.    Activate      1       0
  623.    Deactivate    0       0
  624.    Suspend       0       1
  625.    Resume        1       1
  626.  
  627. =cut
  628. sub activate {
  629.     my($self, $active, $suspend) = @_;
  630.  
  631.     for my $pane (@{$self->{panes}}) { 
  632.         $pane->activate($self, $active, $suspend); 
  633.     };
  634.  
  635.     defined($self->callhook("activate", @_)) and return;
  636.  
  637.     my $focus = $self->{focusable}[$self->{focus}];
  638.     
  639.     $focus->focus($self, $active) if $focus;
  640.     
  641.     1;
  642. }
  643.  
  644. =item update 
  645.  
  646. Handle update events. The default action is to call the redraw function, wrapped
  647. within BeginUpdate/EndUpdate, which is usually the correct thing to do.
  648.  
  649. =cut
  650. sub update {
  651.     defined($_[0]->callhook("update", @_)) and return;
  652.     my($my) = @_;
  653.     my($port) = $my->{port};
  654.     BeginUpdate($port);
  655.     EraseRect($port->portRect);
  656.     $my->drawgrowicon;
  657.     $my->redraw;
  658.     EndUpdate($port);
  659.     1;
  660. }
  661.  
  662. =item drawgrowicon
  663.  
  664. Draw the grow icon, by default for a window without scroll bars. Override as
  665. convenient.
  666.  
  667. =cut
  668. sub drawgrowicon {
  669.     defined($_[0]->callhook("drawgrowicon", @_)) and return;
  670.     my($my) = @_;
  671.     my($port) = $my->{port};
  672.     my($clip) = GetClip();
  673.     my($rect) = $port->portRect;
  674.     $rect->left($rect->right-15);
  675.     $rect->top($rect->bottom-15);
  676.     ClipRect($rect);
  677.     DrawGrowIcon($port);
  678.     SetClip($clip);
  679. }
  680.  
  681. =item redraw
  682.  
  683. Redraw the contents of the window. Override as you'd like, but consider calling
  684. the parent procedure, too.
  685.  
  686. =cut
  687. sub redraw {
  688.     my($self) = @_;
  689.     for my $pane (reverse @{$self->{panes}}) { 
  690.         $pane->redraw($self); 
  691.     };
  692.     defined($self->callhook("redraw", @_)) and return;
  693. }
  694.  
  695. =item key KEY
  696.  
  697. Handle a keypress and return 1 if the key was handled.
  698.  
  699. =cut
  700. sub key {
  701.     my($self, $key) = @_;
  702.     my($handled);
  703.     defined($handled = $self->callhook("key", @_)) and return $handled;
  704.     my $focusable = $self->{focusable};
  705.     
  706.     if ($key == 9 && $self->can_focus) {
  707.         $self->advance_focus(
  708.             $CurrentEvent->modifiers & shiftKey ? -1 : 1);
  709.         return 1;
  710.     }
  711.  
  712.     my $focus = $focusable->[$self->{focus}];
  713.     
  714.     return $focus ? $focus->key($self, $key) : 0;
  715. }
  716.  
  717. =item click PT
  718.  
  719. Handle a mouse click and return 1 if the click was handled.
  720.  
  721. =cut
  722. sub click {
  723.     my($self, $pt) = @_;
  724.     for my $pane (@{$self->{panes}}) { 
  725.         if ($pane->click($self, $pt)) {
  726.             $self->advance_focus($pane);
  727.             return 1; 
  728.         }
  729.     };
  730.     my($handled);
  731.     defined($handled = $self->callhook("click", @_)) and return 1;
  732.     
  733.     1;
  734. }
  735.  
  736. =item drag PT
  737.  
  738. Handle a drag and return 1 if it was handled. Normally doesn't need an
  739. override.
  740.  
  741. =cut
  742. sub drag {
  743.     my($handled);
  744.     defined($handled = $_[0]->callhook("drag", @_)) and return $handled;
  745.     my($my, $pt) = @_;
  746.     
  747.     DragWindow($my->{port}, $pt);
  748.     
  749.     1;
  750. }
  751.  
  752. =item grow PT
  753.  
  754. Handle a drag and return 1 if it was handled. Normally doesn't need an
  755. override.
  756.  
  757. =cut
  758. sub grow {
  759.     my($handled);
  760.     defined($handled = $_[0]->callhook("grow", @_)) and return $handled;
  761.     my($my,$pt) = @_;
  762.     
  763.     if (my($w,$h) = GrowWindow($my->{port}, $pt)) {
  764.         $my->invalgrowarea;
  765.         SizeWindow($my->{port}, $w, $h);
  766.         $my->invalgrowarea;
  767.         $my->layout;
  768.     }
  769.     
  770.     1;
  771. }
  772.  
  773. =item invalgrowarea
  774.  
  775. Invalidate area potentially affected by a size change (grow icon & such).
  776.  
  777. =cut
  778. sub invalgrowarea {
  779.     defined($_[0]->callhook("invalgrowarea", @_)) and return;
  780.     my($my) = @_;
  781.     my($port) = $my->{port};
  782.     my($rect) = $port->portRect;
  783.     $rect->left($rect->right-15);
  784.     $rect->top($rect->bottom-15);
  785.     InvalRect($rect);
  786. }
  787.  
  788. =item layout
  789.  
  790. After a grow, recalculate element positions.
  791.  
  792. =cut
  793. sub layout {
  794.     defined($_[0]->callhook("layout", @_)) and return;
  795. }
  796.  
  797. =item goaway PT
  798.  
  799. Handle a click in the close box and return 1 if it was handled. Normally doesn't 
  800. need an override.
  801.  
  802. =cut
  803. sub goaway {
  804.     my($handled);
  805.     defined($handled = $_[0]->callhook("goaway", @_)) and return $handled;
  806.     my($my,$pt) = @_;
  807.     
  808.     TrackGoAway($my->{port}, $pt) and $my->dispose;
  809.     
  810.     1;
  811. }
  812.  
  813. =item zoom PT, PART
  814.  
  815. Handle a click in the zoom box and return 1 if it was handled. Normally doesn't 
  816. need an override.
  817.  
  818. =cut
  819. sub zoom {
  820.     my($handled);
  821.     defined($handled = $_[0]->callhook("zoom", @_)) and return $handled;
  822.     my($my,$pt,$part) = @_;
  823.     
  824.     if (TrackBox($my->{port}, $pt, $part)) {
  825.         $my->invalgrowarea;
  826.         ZoomWindow($my->{port}, $part, 1);
  827.         $my->invalgrowarea;
  828.         $my->layout;
  829.     }
  830.     
  831.     1;
  832. }
  833.  
  834. =item cursor PT
  835.  
  836. Set the correct cursor for the local point. Defaults to arrow.
  837.  
  838. =cut
  839. sub cursor {
  840.     my($self, $pt) = @_;
  841.     for my $pane (@{$self->{panes}}) { 
  842.         $pane->cursor($self, $pt) and return; 
  843.     };
  844.     my($handled);
  845.     defined($handled = $_[0]->callhook("cursor", @_)) and return $handled;
  846.     SetCursor();
  847. }
  848.  
  849. =item idle
  850.  
  851. Perform regular activities.
  852.  
  853. =cut
  854. sub idle {
  855.     my($self) = @_;
  856.     my($front) = FrontWindow();
  857.     if ($front && ${$self->{port}} == $$front) {
  858.         for my $pane (@{$self->{idlefront}}) { 
  859.             $pane->idle($self); 
  860.         }
  861.     }
  862.     for my $pane (@{$self->{idlealways}}) { 
  863.         $pane->idle($self); 
  864.     }
  865.     $self->callhook("idle", @_);
  866. }
  867.  
  868. =back
  869.  
  870. =head2 MacColorWindow 
  871.  
  872. A C<MacColorWindow> is a C<MacWindow> with a color C<GrafPort>.
  873. =over 4
  874.  
  875. =cut
  876. package MacColorWindow;
  877.  
  878. BEGIN {
  879.     use Carp;
  880.     
  881.     import Mac::Windows;
  882. }
  883.  
  884. =item new MacColorWindow PORT
  885.  
  886. =item new MacColorWindow ID [, BEHIND]
  887.  
  888. =item new MacColorWindow BOUNDS, TITLE, VISIBLE, PROC, GOAWAY [, REFCON [, BEHIND]]
  889.  
  890. Register a new window. In the first form, registers an existing window. In the
  891. second form, calls C<GetNewCWindow>. In the third form, calls C<NewCWindow>.
  892.  
  893. =cut
  894. sub new {
  895.     my($class) = shift @_;
  896.     my($type) = @_;
  897.     my($port);
  898.     
  899.     if (ref($type) eq "Rect") {
  900.         $port = NewCWindow(@_) or croak "NewCWindow failed";
  901.     } elsif (!ref($type)) {
  902.         $port = GetNewCWindow(@_) or croak "GetNewCWindow failed";
  903.     } else {
  904.         $port = $type;
  905.     }
  906.     
  907.     new MacWindow $port;
  908. }
  909.  
  910. package MacWindow;
  911.  
  912. #
  913. # Event handlers
  914. #
  915. sub _MouseDown {
  916.     my($ev) = @_;
  917.     my($code,$win) = FindWindow($ev->where);
  918.     return 0 unless $win;
  919.     my($w) = $Window{$$win};
  920.     return 0 unless $w;
  921.     if ($$win != ${FrontWindow()} && $code != inDrag) {
  922.         SelectWindow($win);
  923.         return 1;
  924.     }
  925.     SetPort($win);
  926.     if ($code == inContent) {
  927.         $w->click(GlobalToLocal($ev->where));
  928.     } elsif ($code == inDrag) {
  929.         $w->drag($ev->where);
  930.     } elsif ($code == inGrow) {
  931.         $w->grow($ev->where);
  932.     } elsif ($code == inGoAway) {
  933.         $w->goaway($ev->where);
  934.     } elsif ($code == inZoomIn || $code == inZoomOut) {
  935.         $w->zoom($ev->where, $code);
  936.     } else {
  937.         0;
  938.     }
  939. }
  940. $Event[mouseDown] = \&_MouseDown;
  941.  
  942. sub _Activate {
  943.     my($ev) = @_;
  944.     my($win) = $ev->window;
  945.     my($w) = $Window{$$win};
  946.     return 0 unless $w;
  947.     SetPort($win);
  948.     $w->activate($ev->modifiers & activeFlag, 0);
  949. }
  950.  
  951. sub _Idle {
  952.     my($ev) = @_;
  953.     
  954.     for my $w (values %Window) {
  955.         $w->idle;
  956.     }
  957.     
  958.     my($code,$win) = FindWindow($ev->where);
  959.     if (!$win || $$win != ${FrontWindow()} || $code != inContent) {
  960.         SetCursor();
  961.         return 1;
  962.     }
  963.     my($w) = $Window{$$win};
  964.     return 0 unless $w;
  965.     SetPort($win);
  966.     $w->cursor(GlobalToLocal($ev->where));
  967. }
  968. $Event[nullEvent] = \&_Idle;
  969.  
  970. sub _OSEvent {
  971.     my($ev) = @_;
  972.     return _Idle($ev) if $ev->osMessage == mouseMovedMessage;
  973.     return 0 unless $ev->osMessage == suspendResumeMessage;
  974.     my($win) = FrontWindow();
  975.     return 0 unless $win;
  976.     my($w) = $Window{$$win};
  977.     return 0 unless $w;
  978.     SetPort($win);
  979.     $w->activate($ev->message & activeFlag, 1);
  980. }
  981. $Event[activateEvt] = \&_Activate;
  982. $Event[osEvt] = \&_OSEvent;
  983.  
  984. sub _Update {
  985.     my($ev) = @_;
  986.     my($win) = $ev->window;
  987.     my($w) = $Window{$$win};
  988.     return 0 unless $w;
  989.     SetPort($win);
  990.     $w->update;
  991. }
  992. $Event[updateEvt] = \&_Update;
  993.  
  994. sub _KeyPress {
  995.     my($ev) = @_;
  996.     my($win) = FrontWindow();
  997.     return 0 unless $win;
  998.     my($w) = $Window{$$win};
  999.     return 0 unless $w;
  1000.     SetPort($win);
  1001.     $w->key($ev->character);
  1002. }
  1003. $Event[keyDown] = \&_KeyPress;
  1004. $Event[autoKey] = \&_KeyPress;
  1005.  
  1006. =head1 BUGS/LIMITATIONS
  1007.  
  1008. =head1 FILES
  1009.  
  1010. =head1 AUTHOR(S)
  1011.  
  1012. Matthias Ulrich Neeracher <neeri@iis.ee.ethz.ch> 
  1013.  
  1014. =cut
  1015.  
  1016. __END__
  1017.