=head1 NAMEMac::Windows - Macintosh Toolbox Interface to Window Manager=head1 SYNOPSIS=head1 DESCRIPTIONAccess to Inside Macintosh is essential for proper use of these functions.Explanations of terms, processes and procedures are provided there.Any attempt to use these functions without guidance can cause severe errors in your machine, including corruption of data. B<You have been warned.>=cut    use strict;package Mac::Windows;BEGIN {    use Exporter   ();    use DynaLoader ();        use vars qw(@ISA @EXPORT @EXPORT_OK);        @ISA = qw(Exporter DynaLoader);    @EXPORT = qw(        GetGrayRgn        GetWMgrPort        NewWindow        GetNewWindow        DisposeWindow        GetWTitle        SelectWindow        HideWindow        ShowWindow        ShowHide        HiliteWindow        BringToFront        SendBehind        FrontWindow        DrawGrowIcon        MoveWindow        SizeWindow        ZoomWindow        InvalRect        InvalRgn        ValidRect        ValidRgn        BeginUpdate        EndUpdate        SetWRefCon        GetWRefCon        SetWindowPic        GetWindowPic        GrowWindow        FindWindow        PinRect        DragGrayRgn        TrackBox        GetCWMgrPort        SetDeskCPat        NewCWindow        GetNewCWindow        GetWVariant        SetWTitle        TrackGoAway        DragWindow        GetWindowKind        SetWindowKind        IsWindowVisible        IsWindowHilited        GetWindowGoAwayFlag        GetWindowZoomFlag        GetWindowStructureRgn        GetWindowContentRgn        GetWindowUpdateRgn        GetWindowTitleWidth        GetNextWindow        GetWindowStandardState        SetWindowStandardState        GetWindowUserState        SetWindowUserState            kWindowDefProcType        kStandardWindowDefinition        kRoundWindowDefinition        kFloatingWindowDefinition        kModalDialogVariantCode        kMovableModalDialogVariantCode        kSideFloaterVariantCode        documentProc        dBoxProc        plainDBox        altDBoxProc        noGrowDocProc        movableDBoxProc        zoomDocProc        zoomNoGrow        rDocProc        floatProc        floatGrowProc        floatZoomProc        floatZoomGrowProc        floatSideProc        floatSideGrowProc        floatSideZoomProc        floatSideZoomGrowProc        kDialogWindowKind        kApplicationWindowKind        inDesk        inMenuBar        inSysWindow        inContent        inDrag        inGrow        inGoAway        inZoomIn        inZoomOut        wDraw        wHit        wCalcRgns        wNew        wDispose        wGrow        wDrawGIcon        deskPatID        wNoHit        wInContent        wInDrag        wInGrow        wInGoAway        wInZoomIn        wInZoomOut        wContentColor        wFrameColor        wTextColor        wHiliteColor        wTitleBarColor    );        @EXPORT_OK = qw(        %Window    );}=head2 Constants=over 4=item kWindowDefProcType=item kStandardWindowDefinition=item kRoundWindowDefinition=item kFloatingWindowDefinition=item kModalDialogVariantCode=item kMovableModalDialogVariantCode=item kSideFloaterVariantCode=item documentProc=item dBoxProc=item plainDBox=item altDBoxProc=item noGrowDocProc=item movableDBoxProc=item zoomDocProc=item zoomNoGrow=item rDocProc=item floatProc=item floatGrowProc=item floatZoomProc=item floatZoomGrowProc=item floatSideProc=item floatSideGrowProc=item floatSideZoomProc=item floatSideZoomGrowProcWindow definition procedure IDs.=cutsub kWindowDefProcType ()          {     'WDEF'; }sub kStandardWindowDefinition ()   {          0; }sub kRoundWindowDefinition ()      {          1; }sub kFloatingWindowDefinition ()   {        124; }sub kModalDialogVariantCode ()     {          1; }sub kMovableModalDialogVariantCode () {       5; }sub kSideFloaterVariantCode ()     {          8; }sub documentProc ()                {          0; }sub dBoxProc ()                    {          1; }sub plainDBox ()                   {          2; }sub altDBoxProc ()                 {          3; }sub noGrowDocProc ()               {          4; }sub movableDBoxProc ()             {          5; }sub zoomDocProc ()                 {          8; }sub zoomNoGrow ()                  {         12; }sub rDocProc ()                    {         16; }sub floatProc ()                   {       1985; }sub floatGrowProc ()               {       1987; }sub floatZoomProc ()               {       1989; }sub floatZoomGrowProc ()           {       1991; }sub floatSideProc ()               {       1993; }sub floatSideGrowProc ()           {       1995; }sub floatSideZoomProc ()           {       1997; }sub floatSideZoomGrowProc ()       {       1999; }=item kDialogWindowKind=item kApplicationWindowKindPredefined window kinds.=cutsub kDialogWindowKind ()           {          2; }sub kApplicationWindowKind ()      {          8; }=item inDesk=item inMenuBar=item inSysWindow=item inContent=item inDrag=item inGrow=item inGoAway=item inZoomIn=item inZoomOutPart codes for C<FindWindow>.=cutsub inDesk ()                      {          0; }sub inMenuBar ()                   {          1; }sub inSysWindow ()                 {          2; }sub inContent ()                   {          3; }sub inDrag ()                      {          4; }sub inGrow ()                      {          5; }sub inGoAway ()                    {          6; }sub inZoomIn ()                    {          7; }sub inZoomOut ()                   {          8; }=item wDraw=item wHit=item wCalcRgns=item wNew=item wDispose=item wGrow=item wDrawGIcon=item deskPatIDPart codes for the draw message to the window definition procedure.=cutsub wDraw ()                       {          0; }sub wHit ()                        {          1; }sub wCalcRgns ()                   {          2; }sub wNew ()                        {          3; }sub wDispose ()                    {          4; }sub wGrow ()                       {          5; }sub wDrawGIcon ()                  {          6; }sub deskPatID ()                   {         16; }=item wNoHit=item wInContent=item wInDrag=item wInGrow=item wInGoAway=item wInZoomIn=item wInZoomOutPart codes for the hit message to the window definition procedure.=cutsub wNoHit ()                      {          0; }sub wInContent ()                  {          1; }sub wInDrag ()                     {          2; }sub wInGrow ()                     {          3; }sub wInGoAway ()                   {          4; }sub wInZoomIn ()                   {          5; }sub wInZoomOut ()                  {          6; }=item wContentColor=item wFrameColor=item wTextColor=item wHiliteColor=item wTitleBarColorColors in window color record.=cutsub wContentColor ()               {          0; }sub wFrameColor ()                 {          1; }sub wTextColor ()                  {          2; }sub wHiliteColor ()                {          3; }sub wTitleBarColor ()              {          4; }=back=cutbootstrap Mac::Windows;=include Windows.xs=head2 MacWindow - The Object InterfaceCorrectly handling a Mac window requires quite a bit of event management. TheC<MacWindow> class relieves you of most of these duties. Most of the eventsreceived are dispatched to a set of panes as defined in C<Mac::Pane>.=over 4=cutpackage MacWindow;BEGIN {    use Carp;    use Mac::Hooks ();    use Mac::Events;    use Mac::Events qw($CurrentEvent @Event);    use Mac::QuickDraw qw(SetPort GlobalToLocal GetClip ClipRect SetClip EraseRect SetCursor);    import Mac::Windows;    import Mac::Windows qw(%Window);    use vars qw(@ISA);        @ISA = qw(Mac::Hooks);}=head2 Creating and Destructing MacWindow objects=item new MacWindow PORT=item new MacWindow ID [, BEHIND]=item new MacWindow BOUNDS, TITLE, VISIBLE, PROC, GOAWAY [, REFCON [, BEHIND]]Register a new window. In the first form, registers an existing window. In thesecond form, calls C<GetNewWindow>. In the third form, calls C<NewWindow>.=cutsub new {    my($class) = shift @_;    my($type) = @_;    my($port);        if (ref($type) eq "Rect") {        $port = NewWindow(@_) or croak "NewWindow failed";    } elsif (!ref($type)) {        $port = GetNewWindow(@_) or croak "GetNewWindow failed";    } else {        $port = $type;    }    my(%vars) =         (port => $port, panes => [], focusable => [], focus => 0,          idlealways => [], idlefront => [], tabbing => 1);    $Window{$$port} = bless \%vars, $class;}=item dispose Unregisters and disposes the window.=cutsub dispose {    my($self) = @_;    return unless $self->{port};        for my $pane (@{$self->{panes}}) {         $pane->detach($self);     };    defined($_[0]->callhook("dispose", @_)) and return;    delete $Window{${$self->{port}}};    DisposeWindow($self->{port});    $self->{port} = "";}sub DESTROY {    my($my) = @_;    $my->dispose;}=back =head2 Accessing Components=over 4=item windowReturns the underlying toolbox C<GrafPtr>.=cutsub window {    my($my) = @_;        $my->{port};}=item add_pane PANEAdds a pane to the window.=cutsub add_pane {    my($self, $pane) = @_;        unshift @{$self->{panes}}, $pane;        $pane->attach($self);}=item remove_pane PANERemoves the pane.=cutsub remove_pane {    my($self, $pane) = @_;        $self->remove_focusable($pane);    $self->remove_idle($pane);        my $panes = $self->{panes};        $pane->detach($self);        @$panes = grep { $_ != $pane } @$panes;}=item add_idle PANE [, FRONT=0]Indicates that the pane needs to get regular time slices. If FRONT is set, thepane only needs time if its window is active.=cutsub add_idle {    my($self, $pane, $front) = @_;    my $idle = $front ? $self->{idlefront} : $self->{idlealways};    push @$idle, $pane;}=item remove_idle PANEIndicates that the pane no longer needs idle time.=cutsub remove_idle {    my($self, $pane) = @_;    my $idle = $self->{idlealways};    @$idle = grep { $_ != $pane } @$idle;    $idle = $self->{idlefront};    @$idle = grep { $_ != $pane } @$idle;   }=item add_focusable PANEIndicates that a pane can get the focus.=cutsub add_focusable {    my($self, $pane) = @_;    my $focusable = $self->{focusable};        push @$focusable, $pane;        $pane->focus($self, 1) if scalar(@$focusable) == 1;}=item remove_focusable PANEIndicates that no instance of this pane can get the focus.=cutsub remove_focusable {    my($self, $pane) = @_;    my $focusable = $self->{focusable};        return unless scalar(@$focusable);        my $focus     = ${$focusable}[$self->{focus}];    my $focused   = $focus == $pane;        $pane->focus($self, 0) if $focused;        @$focusable = grep { $_ != $pane } @$focusable;        if (my $focus_count = scalar(@$focusable)) {        if ($focused) {            $self->{focus} %= $focus_count;            ${$focusable}[$self->{focus}]->focus($self, 1);        } else {            if ($self->{focus} >= scalar(@$focusable)              || ${$focusable}[$self->{focus}] != $focus            ) {                --$self->{focus};            }        }    } else {        $self->{focus} = 0;    }}=item has_focus PANEReturns whether PANE currently is focused.=cutsub has_focus {    my($my, $pane) = @_;    return ${$my->{focusable}}[$my->{focus}] == $pane;}=item can_focus Returns whether there are at least 2 focusable panes.=cutsub can_focus {    my($my) = @_;        return scalar(@{$my->{focusable}}) > 1;}=item advance_focus [STEP]=item advance_focus PANEAdvance the focus by STEP or to PANE.=cutsub advance_focus {    my($my,$step) = @_;    $step ||= 1;    my $focusable = $my->{focusable};    my $max = scalar(@$focusable);    return if $max < 2;    my $focus = $my->{focus};    my $newfocus;    if (ref($step)) {        for ($newfocus=0; $newfocus<$max; ++$newfocus) {            goto switchfocus if $focusable->[$newfocus] == $step;        }        return;    } else {        $newfocus = ($focus+$max+$step) % $max;    }switchfocus:    return if $newfocus == $focus;    $my->{focus} = $newfocus;    $focusable->[$focus]->focus($my, 0);    $focusable->[$newfocus]->focus($my, 1);}=back=head2 Event Handling=over 4=item activate ACTIVE, SUSPENDHandle activation of the window, which is already set to the current port.By default doesn't do anything but update the focus. Override as necessary.The parameters distinguish the four cases:   Event      ACTIVE  SUSPEND      Activate      1       0   Deactivate    0       0   Suspend       0       1   Resume        1       1=cutsub activate {    my($self, $active, $suspend) = @_;    for my $pane (@{$self->{panes}}) {         $pane->activate($self, $active, $suspend);     };    defined($self->callhook("activate", @_)) and return;    my $focus = $self->{focusable}[$self->{focus}];        $focus->focus($self, $active) if $focus;        1;}=item update Handle update events. The default action is to call the redraw function, wrappedwithin BeginUpdate/EndUpdate, which is usually the correct thing to do.=cutsub update {    defined($_[0]->callhook("update", @_)) and return;    my($my) = @_;    my($port) = $my->{port};    BeginUpdate($port);    EraseRect($port->portRect);    $my->drawgrowicon;    $my->redraw;    EndUpdate($port);    1;}=item drawgrowiconDraw the grow icon, by default for a window without scroll bars. Override asconvenient.=cutsub drawgrowicon {    defined($_[0]->callhook("drawgrowicon", @_)) and return;    my($my) = @_;    my($port) = $my->{port};    my($clip) = GetClip();    my($rect) = $port->portRect;    $rect->left($rect->right-15);    $rect->top($rect->bottom-15);    ClipRect($rect);    DrawGrowIcon($port);    SetClip($clip);}=item redrawRedraw the contents of the window. Override as you'd like, but consider callingthe parent procedure, too.=cutsub redraw {    my($self) = @_;    for my $pane (reverse @{$self->{panes}}) {         $pane->redraw($self);     };    defined($self->callhook("redraw", @_)) and return;}=item key KEYHandle a keypress and return 1 if the key was handled.=cutsub key {    my($self, $key) = @_;    my($handled);    defined($handled = $self->callhook("key", @_)) and return $handled;    my $focusable = $self->{focusable};        if ($key == 9 && $self->can_focus) {        $self->advance_focus(            $CurrentEvent->modifiers & shiftKey ? -1 : 1);        return 1;    }    my $focus = $focusable->[$self->{focus}];        return $focus ? $focus->key($self, $key) : 0;}=item click PTHandle a mouse click and return 1 if the click was handled.=cutsub click {    my($self, $pt) = @_;    for my $pane (@{$self->{panes}}) {         if ($pane->click($self, $pt)) {            $self->advance_focus($pane);            return 1;         }    };    my($handled);    defined($handled = $self->callhook("click", @_)) and return 1;        1;}=item drag PTHandle a drag and return 1 if it was handled. Normally doesn't need anoverride.=cutsub drag {    my($handled);    defined($handled = $_[0]->callhook("drag", @_)) and return $handled;    my($my, $pt) = @_;        DragWindow($my->{port}, $pt);        1;}=item grow PTHandle a drag and return 1 if it was handled. Normally doesn't need anoverride.=cutsub grow {    my($handled);    defined($handled = $_[0]->callhook("grow", @_)) and return $handled;    my($my,$pt) = @_;        if (my($w,$h) = GrowWindow($my->{port}, $pt)) {        $my->invalgrowarea;        SizeWindow($my->{port}, $w, $h);        $my->invalgrowarea;        $my->layout;    }        1;}=item invalgrowareaInvalidate area potentially affected by a size change (grow icon & such).=cutsub invalgrowarea {    defined($_[0]->callhook("invalgrowarea", @_)) and return;    my($my) = @_;    my($port) = $my->{port};    my($rect) = $port->portRect;    $rect->left($rect->right-15);    $rect->top($rect->bottom-15);    InvalRect($rect);}=item layoutAfter a grow, recalculate element positions.=cutsub layout {    defined($_[0]->callhook("layout", @_)) and return;}=item goaway PTHandle a click in the close box and return 1 if it was handled. Normally doesn't need an override.=cutsub goaway {    my($handled);    defined($handled = $_[0]->callhook("goaway", @_)) and return $handled;    my($my,$pt) = @_;        TrackGoAway($my->{port}, $pt) and $my->dispose;        1;}=item zoom PT, PARTHandle a click in the zoom box and return 1 if it was handled. Normally doesn't need an override.=cutsub zoom {    my($handled);    defined($handled = $_[0]->callhook("zoom", @_)) and return $handled;    my($my,$pt,$part) = @_;        if (TrackBox($my->{port}, $pt, $part)) {        $my->invalgrowarea;        ZoomWindow($my->{port}, $part, 1);        $my->invalgrowarea;        $my->layout;    }        1;}=item cursor PTSet the correct cursor for the local point. Defaults to arrow.=cutsub cursor {    my($self, $pt) = @_;    for my $pane (@{$self->{panes}}) {         $pane->cursor($self, $pt) and return;     };    my($handled);    defined($handled = $_[0]->callhook("cursor", @_)) and return $handled;    SetCursor();}=item idlePerform regular activities.=cutsub idle {    my($self) = @_;    my($front) = FrontWindow();    if ($front && ${$self->{port}} == $$front) {        for my $pane (@{$self->{idlefront}}) {             $pane->idle($self);         }    }    for my $pane (@{$self->{idlealways}}) {         $pane->idle($self);     }    $self->callhook("idle", @_);}=back=head2 MacColorWindow A C<MacColorWindow> is a C<MacWindow> with a color C<GrafPort>.=over 4=cutpackage MacColorWindow;BEGIN {    use Carp;        import Mac::Windows;}=item new MacColorWindow PORT=item new MacColorWindow ID [, BEHIND]=item new MacColorWindow BOUNDS, TITLE, VISIBLE, PROC, GOAWAY [, REFCON [, BEHIND]]Register a new window. In the first form, registers an existing window. In thesecond form, calls C<GetNewCWindow>. In the third form, calls C<NewCWindow>.=cutsub new {    my($class) = shift @_;    my($type) = @_;    my($port);        if (ref($type) eq "Rect") {        $port = NewCWindow(@_) or croak "NewCWindow failed";    } elsif (!ref($type)) {        $port = GetNewCWindow(@_) or croak "GetNewCWindow failed";    } else {        $port = $type;    }        new MacWindow $port;}package MacWindow;## Event handlers#sub _MouseDown {    my($ev) = @_;    my($code,$win) = FindWindow($ev->where);    return 0 unless $win;    my($w) = $Window{$$win};    return 0 unless $w;    if ($$win != ${FrontWindow()} && $code != inDrag) {        SelectWindow($win);        return 1;    }    SetPort($win);    if ($code == inContent) {        $w->click(GlobalToLocal($ev->where));    } elsif ($code == inDrag) {        $w->drag($ev->where);    } elsif ($code == inGrow) {        $w->grow($ev->where);    } elsif ($code == inGoAway) {        $w->goaway($ev->where);    } elsif ($code == inZoomIn || $code == inZoomOut) {        $w->zoom($ev->where, $code);    } else {        0;    }}$Event[mouseDown] = \&_MouseDown;sub _Activate {    my($ev) = @_;    my($win) = $ev->window;    my($w) = $Window{$$win};    return 0 unless $w;    SetPort($win);    $w->activate($ev->modifiers & activeFlag, 0);}sub _Idle {    my($ev) = @_;        for my $w (values %Window) {        $w->idle;    }        my($code,$win) = FindWindow($ev->where);    if (!$win || $$win != ${FrontWindow()} || $code != inContent) {        SetCursor();        return 1;    }    my($w) = $Window{$$win};    return 0 unless $w;    SetPort($win);    $w->cursor(GlobalToLocal($ev->where));}$Event[nullEvent] = \&_Idle;sub _OSEvent {    my($ev) = @_;    return _Idle($ev) if $ev->osMessage == mouseMovedMessage;    return 0 unless $ev->osMessage == suspendResumeMessage;    my($win) = FrontWindow();    return 0 unless $win;    my($w) = $Window{$$win};    return 0 unless $w;    SetPort($win);    $w->activate($ev->message & activeFlag, 1);}$Event[activateEvt] = \&_Activate;$Event[osEvt] = \&_OSEvent;sub _Update {    my($ev) = @_;    my($win) = $ev->window;    my($w) = $Window{$$win};    return 0 unless $w;    SetPort($win);    $w->update;}$Event[updateEvt] = \&_Update;sub _KeyPress {    my($ev) = @_;    my($win) = FrontWindow();    return 0 unless $win;    my($w) = $Window{$$win};    return 0 unless $w;    SetPort($win);    $w->key($ev->character);}$Event[keyDown] = \&_KeyPress;$Event[autoKey] = \&_KeyPress;=head1 BUGS/LIMITATIONS=head1 FILES=head1 AUTHOR(S)Matthias Ulrich Neeracher <neeri@iis.ee.ethz.ch> =cut__END__