sources/UsherBroadcast.c

/*
    File:       UsherBroadcast.c
 
    Copyright:  © 2000-2001 by Apple Computer, Inc., all rights reserved.
 
 
*/
 
#include <ConditionalMacros.h>
#include <Files.h>
#include <Resources.h>
#include <ToolUtils.h>
 
#include <string.h>
 
#include <QuicktimeComponents.h>
#include <MoviesFormat.h>
#include <Movies.h>
 
#include <QuickTimeStreaming.h>
#include <QTStreamingComponents.h>
 
 
#include "AppSupport.h"
#include "QTSSampleCodeUtils.h"
#include "SimplePres.h"
#include "SourcingSupport.h"
#include "WindowSupport.h"
#include "UsherBroadcast.h"
 
#include "UsherRezDefines.h"
#include "UsherCommands.h"
    
// ---------------------------------------------------------------------------
//      D E F I N I T I O N S
// ---------------------------------------------------------------------------
 
 
 
// ---------------------------------------------------------------------------
//      P R O T O T Y P E S
// ---------------------------------------------------------------------------
 
 
static void UsherBroadcastPriv_SetNameFromFile(UsherBroadcast *inBroadcast, const FSSpec *inFileSpec);
 
// ----- commands -----
 
static OSErr UsherBroadcastPriv_GetBroadcastName(UsherBroadcast *inBroadcast, UsherBroadcastStringParams *inParams);
static OSErr UsherBroadcastPriv_GetStateString(UsherBroadcast *inBroadcast, UsherBroadcastStringParams *inParams);
static OSErr UsherBroadcastPriv_GetBroadcastTime(UsherBroadcast *inBroadcast, UsherBroadcastTimeParams *inTimeParams);
 
// ----- notifications -----
 
static ComponentResult _UsherBroadcastNotification(ComponentResult inErr, OSType inNotificationType,
                                void *inNotificationParams, void *inRefCon);
 
static ComponentResult UsherBroadcastPriv_HandleErrorNotification(UsherBroadcast *inBroadcast,
            ComponentResult inErr, QTSErrorParams *inErrorParams);
 
 
// ----- infrastructure support -----
 
static void UsherBroadcastPriv_AddToList(UsherBroadcast *inBroadcast);
static void UsherBroadcastPriv_RemoveFromList(UsherBroadcast *inBroadcast);
 
static void UsherBroadcastPriv_SendMessage(UsherBroadcast *inBroadcast, long inMessage, void *inMessageParams);
 
// ---------------------------------------------------------------------------
//      U P P   S T U F F
// ---------------------------------------------------------------------------
 
static QTSNotificationUPP sUsherBroadcastNotificationUPP = NULL;
 
// ---------------------------------------------------------------------------
//      G L O B A L S
// ---------------------------------------------------------------------------
 
static UsherBroadcast   *sUsherPresList = NULL;
static Boolean          sUsherPresShuttingDown = false;
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_NewFromFile
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_NewFromFile(const FSSpec *inFileSpec, GWorldPtr inGWorld, GDHandle inGD,
                        const Rect *inPresBox, UsherBroadcast **outBroadcast)
{
    OSErr                   err = noErr;
    UsherBroadcast          *broadcast = NULL;
    char                    tempString[255];
    
    broadcast = (UsherBroadcast*)QTSNewPtrClear(sizeof(UsherBroadcast));
    EXITIFERR( err = MemError() );
    broadcast->signature = kUsherBroadcastSignature;
    
    UsherBroadcastPriv_AddToList(broadcast);
    
    EXITIFERR( err = SimplePres_NewFromFile(inFileSpec, inGWorld, inGD, inPresBox, &broadcast->simplePres) );
    
    EXITIFERR( err = QTSPresGetTimeBase(SimplePres_GetPresentation(broadcast->simplePres), &broadcast->presTimeBase) );
    EXITIFERR( err = QTSPresGetTimeScale(SimplePres_GetPresentation(broadcast->simplePres), &broadcast->presTimeScale) );
    
    if (sUsherBroadcastNotificationUPP == NULL)  {
        sUsherBroadcastNotificationUPP = (QTSNotificationUPP)NewQTSNotificationUPP(_UsherBroadcastNotification);
    }
    SimplePres_SetOwnerNotification(broadcast->simplePres, sUsherBroadcastNotificationUPP, (void*)broadcast);
 
        
    UsherBroadcastPriv_SetNameFromFile(broadcast, inFileSpec);
 
    if (outBroadcast != NULL)  {
        *outBroadcast = broadcast;
    }
 
exit:
    CopyPToCStr(inFileSpec->name, tempString);
    if (err != noErr)  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
                "UsherBroadcast_NewFromFile err %ld creating '%s'", err, tempString);
        if (broadcast != NULL)  {
            UsherBroadcast_Dispose(broadcast);
        }
    }  else  {
        ProcessUserMessage(kProcessMessageFlag_Log,
                "New broadcast created from '%s'", tempString);
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_SetNameFromFile
// ---------------------------------------------------------------------------
 
static void UsherBroadcastPriv_SetNameFromFile(UsherBroadcast *inBroadcast, const FSSpec *inFileSpec)
{
    int                     length;
    const unsigned char     *current;
 
    // strip off any extensions
    length = inFileSpec->name[0];
    current = &(inFileSpec->name[length-1]);
    while (current > inFileSpec->name) {
        if (current[0] == '.')  {
            break;
        }
        --current;
    }
    if (current > inFileSpec->name)  {
        CopyPToCStrn(inFileSpec->name, inBroadcast->presName, current - inFileSpec->name - 1);
    }  else  {
        CopyPToCStr(inFileSpec->name, inBroadcast->presName);
    }
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_Dispose
// ---------------------------------------------------------------------------
 
void UsherBroadcast_Dispose(UsherBroadcast *inBroadcast)
{
    SInt32              i;
 
    if (inBroadcast != NULL)  {     
        if (inBroadcast->disposing)  {
            goto exit;
        }
        inBroadcast->disposing = true;
 
        for (i=0; i<inBroadcast->numSourceHandlers; ++i)  {
            SourcingSupport_DisposeHandler(inBroadcast->sourceHandlers[i].handler);
            inBroadcast->sourceHandlers[i].handler = 0;
        }
        inBroadcast->numSourceHandlers = 0;
 
        for (i=0; i<inBroadcast->numWindows; ++i)  {
            //@@@ should ask if the window wants to be closed...    
            WindowSupport_CloseWindow(inBroadcast->windowList[i]);
        }
        inBroadcast->numWindows = 0;
        
        
        if (inBroadcast->simplePres != NULL)  {
            SimplePres_Dispose(inBroadcast->simplePres);
        }
 
        UsherBroadcastPriv_RemoveFromList(inBroadcast);
        DisposePtr((Ptr)inBroadcast);
    }
exit:
    return;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_GetMenuCommand
// ---------------------------------------------------------------------------
 
long UsherBroadcast_GetMenuCommand(UsherBroadcast *inBroadcast, long inMenuResult, void **outCommandParams)
{
#pragma unused(inBroadcast, outCommandParams)
    short                   menuID, menuItem;
    SInt32                  command = kCommand_Nothing;
 
    menuID = MYHIWORD(inMenuResult);
    menuItem = MYLOWORD(inMenuResult);
    switch (menuID)  {
        case rMenu_File:
            switch (menuItem)  {
                case rMenuItem_Export:
                    command = kCommand_PresExport;
                    break;
                default:
                    break;
            }
            break;
 
        case rMenu_Presentation:
            switch (menuItem)  {
                case rMenuItem_SettingsDialog:
                    command = kCommand_PresSettingsDialog;
                    break;
                default:
                    break;
            }
            break;
 
 
        default:
            break;
    }
    
exit:
    return command;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_DoCommand
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_DoCommand(UsherBroadcast *inBroadcast, long inCommand, void *ioCommandParams)
{
    OSErr               err = noErr;
    
    switch (inCommand)  {
            
        case kCommand_PresSettingsDialog:
            err = SimplePres_SettingsDialog(inBroadcast->simplePres);
            break;
 
        case kCommand_PresExport:
            err = SimplePres_ExportToFile(inBroadcast->simplePres, AppGlobals_GetAppSignature());
            break;
 
 
        case kCommand_GetBroadcastName:
            err = UsherBroadcastPriv_GetBroadcastName(inBroadcast, (UsherBroadcastStringParams*)ioCommandParams);
            break;
        
        case kCommand_GetBroadcastStateString:
            err = UsherBroadcastPriv_GetStateString(inBroadcast, (UsherBroadcastStringParams*)ioCommandParams);
            break;
 
        case kCommand_GetBroadcastTime:
            err = UsherBroadcastPriv_GetBroadcastTime(inBroadcast, (UsherBroadcastTimeParams*)ioCommandParams);
            break;
 
        default:
        {
            long        i;
            
            err = kErr_AppUnhandledCommand;
            // ask the handlers
            for (i=0; i<inBroadcast->numSourceHandlers; ++i)  {
                err = SourcingSupport_DoCommand(inBroadcast->sourceHandlers[i].handler, inCommand, ioCommandParams);
                if (err != kErr_AppUnhandledCommand)  {
                    break;
                }           
            }
            break;
        }
    }
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_GetBroadcastName
// ---------------------------------------------------------------------------
 
static OSErr UsherBroadcastPriv_GetBroadcastName(UsherBroadcast *inBroadcast,
                    UsherBroadcastStringParams *inParams)
{
    OSErr       err = noErr;
    UInt32      length;
 
    if (inParams == NULL)  {
        DEBUGF(("UsherBroadcastPriv_GetBroadcastName $%.8x-null params", inBroadcast));
        EXITERR( err = paramErr );
    }
    if (inParams->ioString == NULL)  {
        DEBUGF(("UsherBroadcastPriv_GetBroadcastName $%.8x-null string param", inBroadcast));
        EXITERR( err = paramErr );
    }
    length = strlen(inBroadcast->presName);
    if (length > inParams->inMaxLength)  {
        length = inParams->inMaxLength;
    }
    BlockMoveData(inBroadcast->presName, inParams->ioString, length);
    inParams->ioString[length] = '\0';
    inParams->returnedStringLength = length;
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_GetStateString
// ---------------------------------------------------------------------------
 
static OSErr UsherBroadcastPriv_GetStateString(UsherBroadcast *inBroadcast,
                    UsherBroadcastStringParams *inParams)
{
    OSErr               err = noErr;
    UInt32              length;
    Str255              tempString;
    SimplePresState     state;
 
    if (inParams == NULL)  {
        DEBUGF(("UsherBroadcastPriv_GetStateString $%.8x-null params", inBroadcast));
        EXITERR( err = paramErr );
    }
    if (inParams->ioString == NULL)  {
        DEBUGF(("UsherBroadcastPriv_GetStateString $%.8x-null string param", inBroadcast));
        EXITERR( err = paramErr );
    }
 
    state = SimplePres_GetState(inBroadcast->simplePres);
 
    if (state == 0)  {
        DEBUGF(("UsherBroadcastPriv_GetStateString $%.8x-state==0", inBroadcast));
        EXITERR( err = paramErr );
    }
    GetIndString(tempString, rStringList_PresState, state);
    length = tempString[0];
    if (length > inParams->inMaxLength)  {
        length = inParams->inMaxLength;
    }
 
    BlockMoveData(&(tempString[1]), inParams->ioString, length);
    inParams->ioString[length] = '\0';
    inParams->returnedStringLength = length;
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_GetBroadcastTime
// ---------------------------------------------------------------------------
 
static OSErr UsherBroadcastPriv_GetBroadcastTime(UsherBroadcast *inBroadcast,
                    UsherBroadcastTimeParams *inTimeParams)
{
    OSErr       err = noErr;
 
    if (inTimeParams->timeScale == 0)  {
        inTimeParams->timeScale = inBroadcast->presTimeScale;
    }
    QTSGetTimeBaseTime64(inBroadcast->presTimeBase, inTimeParams->timeScale, &inTimeParams->returnedTime);
exit:
    return err;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_Idle
// ---------------------------------------------------------------------------
 
void UsherBroadcast_Idle(UsherBroadcast *inBroadcast)
{
    long        i;
    Boolean     playing = false;
 
    if (inBroadcast != NULL)  {
        if (inBroadcast->simplePres != NULL)  {
            SimplePres_Idle(inBroadcast->simplePres);
            playing = (SimplePres_GetState(inBroadcast->simplePres) == kSimplePresState_Playing);
        }
 
        for (i=0; i<inBroadcast->numSourceHandlers; ++i)  {
            SourcingSupport_Idle(inBroadcast->sourceHandlers[i].handler, playing);
        }
 
        // idle all the windows
        for (i=0; i<inBroadcast->numWindows; ++i)  {
            WindowSupport_Idle(inBroadcast->windowList[i]);
        }
    }
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_Start
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_Start(UsherBroadcast *inBroadcast)
{
    OSErr           err = noErr;
 
    if (inBroadcast->simplePres == NULL)  {
        DEBUGF(("UsherBroadcast_Start $%.8x - null presentation", inBroadcast));
        EXITERR( err = qtsBadStateErr );
    }
    
    err = SimplePres_Start(inBroadcast->simplePres);
            
exit:
    if (err == noErr)  {
        ProcessUserMessage(kProcessMessageFlag_Log,
                "Broadcast '%s' started", inBroadcast->presName);
    }  else  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
                "Error (%ld) starting broadcast '%s'", err, inBroadcast->presName);
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_Stop
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_Stop(UsherBroadcast *inBroadcast)
{
    OSErr           err = noErr;
 
    if (inBroadcast->simplePres == NULL)  {
        DEBUGF(("UsherBroadcast_Stop $%.8x - null presentation", inBroadcast));
        EXITERR( err = qtsBadStateErr );
    }
    err = SimplePres_Stop(inBroadcast->simplePres);
exit:
    ProcessUserMessage(kProcessMessageFlag_Log,
                "Broadcast '%s' stopped", inBroadcast->presName);
    return err;
}
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      _UsherBroadcastNotification
// ---------------------------------------------------------------------------
 
static ComponentResult _UsherBroadcastNotification(ComponentResult inErr, OSType inNotificationType,
                                void *inNotificationParams, void *inRefCon)
{
    UsherBroadcast      *broadcast = (UsherBroadcast*)inRefCon;
    ComponentResult     err = noErr;
    
    switch (inNotificationType)  {
    
        case kQTSPrerollAckNotification:
        case kQTSStartAckNotification:
        case kQTSStopAckNotification:
            // apps should put up some nice ui about the error
            if (inErr != NULL)  {
                //DEBUGF(("_UsherBroadcastNotification $%.8x type $%.8x, err %ld", broadcast, inNotificationType, inErr));
            }
            UsherBroadcastPriv_SendMessage(broadcast, kMessage_SendPresStateChanged, (void*) SimplePres_GetState(broadcast->simplePres));
 
            break;
                
        case kQTSErrorNotification:
            //err = UsherBroadcastPriv_HandleErrorNotification(broadcast, inErr, (QTSErrorParams*)inNotificationParams);
            break;
    
        default:
            // it's ok to get a notification you don't know about
            // just silently ignore it
            break;
    }
    
    if (broadcast->someHandlerWantsNotifications)  {
        long        i;
        
        for (i=0; i<broadcast->numSourceHandlers; ++i)  {
            if (broadcast->sourceHandlers[i].handlerWantsNotifications)  {
                SourcingSupport_HandleNotification(broadcast->sourceHandlers[i].handler, inNotificationType, inNotificationParams);
            }
        }
    }
    
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_HandleErrorNotification
// ---------------------------------------------------------------------------
 
static ComponentResult UsherBroadcastPriv_HandleErrorNotification(UsherBroadcast *inBroadcast,
            ComponentResult inErr, QTSErrorParams *inErrorParams)
{
#pragma unused(inBroadcast, inErrorParams)
    // tell the user in some nice way
    // inErrorParams can be NULL
    if (inErrorParams == NULL)  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
                "Error (%ld) in broadcast", inErr);
    }  else  {
        ProcessUserMessage(kProcessMessageFlag_Log | kProcessMessageFlag_ShowDialog,
                "Error (%ld) in broadcast '%s'", inErr, inErrorParams->errorString);
    }
    return noErr;
}
 
 
#pragma mark -
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_GetStatusParams
// ---------------------------------------------------------------------------
 
QTSStatusParams *UsherBroadcast_GetStatusParams(UsherBroadcast *inBroadcast)
{
    QTSStatusParams     *statusParams = NULL;
    
    if (inBroadcast != NULL)  {
        statusParams = &inBroadcast->statusParams;
    }   
    return statusParams;    
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_GetQTSPresentation
// ---------------------------------------------------------------------------
 
QTSPresentation UsherBroadcast_GetQTSPresentation(UsherBroadcast *inBroadcast)
{
    QTSPresentation     presentation = kQTSInvalidPresentation;
    
    if (inBroadcast->simplePres != NULL)  {
        presentation = SimplePres_GetPresentation(inBroadcast->simplePres);
    }   
    return presentation;    
}
 
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_GetInfo
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_GetInfo(UsherBroadcast *inBroadcast, OSType inSelector, void *ioParams)
{
    OSErr           err = noErr;
    Boolean         sendToPres = false;
    long            i;
    
    switch (inSelector)  {
        case kQTSInfo_SourcerTiming:
        {
            for (i=0; i<inBroadcast->numSourceHandlers; ++i)  {
                err = SourcingSupport_GetInfo(inBroadcast->sourceHandlers[i].handler, inSelector, ioParams);
                if (err == noErr)  {
                    break;
                }
            }
            break;
        }
 
 
        default:
            sendToPres = true;
            err = qtsBadSelectorErr;
            break;
    }
 
    if (sendToPres  &&  (inBroadcast->simplePres != NULL))  {
        err = SimplePres_GetInfo(inBroadcast->simplePres, inSelector, ioParams);
    }  else  {
        if (inBroadcast->simplePres == NULL)  {
            DEBUGF(("UsherBroadcast_GetInfo $%.8x - info $%.8x no presentation", inBroadcast, inSelector));
        }
    }
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_SetInfo
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_SetInfo(UsherBroadcast *inBroadcast, OSType inSelector, void *ioParams)
{
    OSErr           err = noErr;
    Boolean         sendToPres = false;
 
    switch (inSelector)  {
        default:
            sendToPres = true;
            err = qtsBadSelectorErr;
            break;
    }
 
    if (inBroadcast->simplePres != NULL)  {
        err = SimplePres_SetInfo(inBroadcast->simplePres, inSelector, ioParams);
    }  else  {
        DEBUGF(("UsherBroadcast_SetInfo $%.8x - info $%.8x no presentation", inBroadcast, inSelector));
    }
    return err;
}
 
 
#pragma mark -
#pragma mark .----- infrastructure support -----
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_GetNumBroadcasts
// ---------------------------------------------------------------------------
 
long UsherBroadcast_GetNumBroadcasts(void)
{
    long                numBroadcasts = 0;
    UsherBroadcast      *current;
 
    current = sUsherPresList;
    while (current != NULL)  {
        ++numBroadcasts;
        current = current->next;
    }
    return numBroadcasts;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_IdleAll
// ---------------------------------------------------------------------------
 
void UsherBroadcast_IdleAll(void)
{
    UsherBroadcast      *current;
 
    current = sUsherPresList;
    while (current != NULL)  {
        UsherBroadcast_Idle(current);
        current = current->next;
    }
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_CleanUp
// ---------------------------------------------------------------------------
 
void UsherBroadcast_CleanUp(void)
{
    // for every presentation in the list, get rid of it
    UsherBroadcast      *current;
    UsherBroadcast      *next;
    
    sUsherPresShuttingDown = true;
    current = sUsherPresList;
    sUsherPresList = NULL;
    while (current != NULL)  {
        next = current->next;
        UsherBroadcast_Dispose(current);
        current = next;
    }
    sUsherPresShuttingDown = false;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_AddToList
// ---------------------------------------------------------------------------
 
static void UsherBroadcastPriv_AddToList(UsherBroadcast *inBroadcast)
{
    inBroadcast->next = sUsherPresList;
    sUsherPresList = inBroadcast;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_RemoveFromList
// ---------------------------------------------------------------------------
 
static void UsherBroadcastPriv_RemoveFromList(UsherBroadcast *inBroadcast)
{
    UsherBroadcast      *current;
    UsherBroadcast      *prev = NULL;
 
    if (!sUsherPresShuttingDown)  {
        current = sUsherPresList;
        while (current != NULL)  {
            if (current == inBroadcast)  {
                if (prev != NULL)  {
                    prev->next = current->next;
                }  else  {
                    sUsherPresList = current->next;
                }
                break;
            }
            prev = current;
            current = current->next;
        }
    }
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_AddSourceHandler
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_AddSourceHandler(UsherBroadcast *inBroadcast, void *inSourceHandler)
{
    OSErr           err = noErr;
    Boolean         wantsNotifications = false;
    
    if (inBroadcast->numSourceHandlers >= kUsherBroadcastMaxSourceHandlers)  {
        DEBUGF(("UsherBroadcast_AddSourceHandler $%.8x - already have max %ld handlers", inBroadcast, kUsherBroadcastMaxSourceHandlers));
        EXITERR( err = qtsBadStateErr );
    }
    
    inBroadcast->sourceHandlers[inBroadcast->numSourceHandlers].handler = inSourceHandler;
    SourcingSupport_HasCharacteristic(inSourceHandler, kCharacteristic_WantsPresNotifications, &wantsNotifications);
    inBroadcast->sourceHandlers[inBroadcast->numSourceHandlers].handlerWantsNotifications = wantsNotifications;
    if (wantsNotifications)  {
        inBroadcast->someHandlerWantsNotifications = true;
    }
    ++(inBroadcast->numSourceHandlers);
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_AddWindow
// ---------------------------------------------------------------------------
 
OSErr UsherBroadcast_AddWindow(UsherBroadcast *inBroadcast, WindowPtr inWindow)
{
    OSErr           err = noErr;
    
    if (inBroadcast->numWindows >= kUsherBroadcastMaxWindows)  {
        DEBUGF(("UsherBroadcast_AddWindow $%.8x - already have max %ld windows", inBroadcast, kUsherBroadcastMaxWindows));
        EXITERR( err = qtsBadStateErr );
    }
    
    inBroadcast->windowList[inBroadcast->numWindows] = inWindow;
    ++(inBroadcast->numWindows);
exit:
    return err;
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcast_RemoveWindow
// ---------------------------------------------------------------------------
 
void UsherBroadcast_RemoveWindow(UsherBroadcast *inBroadcast, WindowPtr inWindow)
{
    SInt32          i;
    
    for (i=0; i<inBroadcast->numWindows; ++i)  {
        if  (inWindow == inBroadcast->windowList[i])  {
            // move the other windows up
            if (i<inBroadcast->numWindows-1)  {
                BlockMoveData(&(inBroadcast->windowList[i+1]),
                            &(inBroadcast->windowList[i]), (inBroadcast->numWindows-1-i));
            }
            --(inBroadcast->numWindows);
            break;
        }
    }
    if (inBroadcast->numWindows == 0)  {
        UsherBroadcast_Dispose(inBroadcast);
    }   
}
 
// ---------------------------------------------------------------------------
//      UsherBroadcastPriv_SendMessage
// ---------------------------------------------------------------------------
 
static void UsherBroadcastPriv_SendMessage(UsherBroadcast *inBroadcast, long inMessage, void *inMessageParams)
{
    long            i;
 
    // tell all the windows
    for (i=0; i<inBroadcast->numWindows; ++i)  {
        WindowSupport_HandleMessage(inBroadcast->windowList[i], inMessage, inMessageParams);
    }
}