1/* 2 * MovieCallBack.c -- 3 * 4 * Process the "callback" subcommand. 5 * 6 * Copyright (c) 2003 Mats Bengtsson 7 * 8 * $Id: MovieCallBack.c,v 1.3 2003/12/02 10:17:03 matben Exp $ 9 */ 10 11#include "MoviePlayer.h" 12 13 14/* 15 * For dispatching 'callback' sub commands. 16 */ 17 18static char *allCallBackCmds[] = { 19 "cancel", "info", 20 (char *) NULL 21}; 22 23enum { 24 kCallBackCmdCancel = 0L, 25 kCallBackCmdInfo 26}; 27 28/* 29 * Use hash table to map between token names and the corresponding 30 * callback struct entry. 31 */ 32 33typedef struct CallBackEntry { 34 MoviePlayer *movPtr; 35 TimeValue movTime; 36 long uid; 37 Tcl_Obj *cmdObjPtr; 38 QTCallBack callback; 39 Tcl_HashEntry *hashPtr; /* Self referencing; useful when freeing */ 40} CallBackEntry; 41 42static char gTokenCallbackStr[] = "moviecallback"; 43static long gTokenUID = 0; 44 45pascal void CallBackProc( QTCallBack cb, long refCon ); 46 47/* 48 *---------------------------------------------------------------------- 49 * 50 * ProcessCallBackCmd -- 51 * 52 * Process the "callback" command 53 * 54 * Results: 55 * Normal TCL results 56 * 57 * Side effects: 58 * Sets up or cancels callbacks, or just returns info. 59 * 60 *---------------------------------------------------------------------- 61 */ 62 63int 64ProcessCallBackCmd( 65 MoviePlayer *movPtr, 66 int objc, /* Starts with the thing after 'callback' */ 67 Tcl_Obj *CONST objv[] ) 68{ 69 Tcl_Interp *interp = movPtr->interp; 70 Movie theMovie = movPtr->aMovie; 71 int cmdIndex; 72 int isNew; 73 long movTime; 74 Tcl_HashTable *callBackHashTablePtr = movPtr->callBackHashTablePtr; 75 Tcl_HashSearch search; 76 Tcl_HashEntry *hashPtr = NULL; 77 Tcl_Obj *objPtr; 78 Tcl_Obj *listObjPtr; 79 CallBackEntry *entryPtr; 80 OSErr err = noErr; 81 int result = TCL_OK; 82 83 if (callBackHashTablePtr == NULL) { 84 movPtr->callBackHashTablePtr = (Tcl_HashTable *) 85 ckalloc( sizeof(Tcl_HashTable) ); 86 callBackHashTablePtr = movPtr->callBackHashTablePtr; 87 Tcl_InitHashTable( callBackHashTablePtr, TCL_STRING_KEYS ); 88 } 89 if (objc < 1) { 90 Tcl_WrongNumArgs( interp, 0, objv, 91 "pathName callback time|cmd ?args?" ); 92 return TCL_ERROR; 93 } 94 95 /* 96 * Either a command (cancel or info) or an integer number. 97 */ 98 99 if (Tcl_GetIndexFromObj( interp, objv[0], allCallBackCmds, "callback command", 100 TCL_EXACT, &cmdIndex ) != TCL_OK ) { 101 if (Tcl_GetLongFromObj( interp, objv[0], &movTime ) == TCL_OK) { 102 cmdIndex = -1; 103 } else { 104 Tcl_SetObjResult( interp, Tcl_NewStringObj( 105 "Usage: \"pathName callback time|cmd ?args?\"", -1 ) ); 106 return TCL_ERROR; 107 } 108 } 109 110 /* 111 * Dispatch the callback command to the right branch. 112 */ 113 114 switch (cmdIndex) { 115 116 case -1: { 117 char tmpstr[32]; 118 119 if (objc != 2) { 120 Tcl_WrongNumArgs( interp, 0, objv, 121 "pathName callback time procName" ); 122 return TCL_ERROR; 123 } 124 if (Tcl_GetLongFromObj( interp, objv[0], &movTime ) != TCL_OK) { 125 Tcl_AddErrorInfo( interp, "\n (processing time value)" ); 126 return TCL_ERROR; 127 } 128 entryPtr = (CallBackEntry *) ckalloc( sizeof(CallBackEntry) ); 129 entryPtr->callback = NewCallBack( GetMovieTimeBase( theMovie ), 130 callBackAtTime ); 131 entryPtr->uid = gTokenUID; 132 entryPtr->movPtr = movPtr; 133 entryPtr->movTime = movTime; 134 err = CallMeWhen( entryPtr->callback, 135 NewQTCallBackUPP( CallBackProc), (long) entryPtr, 136 triggerTimeEither, movTime, GetMovieTimeScale( theMovie ) ); 137 138 entryPtr->cmdObjPtr = objv[1]; 139 Tcl_IncrRefCount( objv[1] ); 140 sprintf( tmpstr, "%s%ld", gTokenCallbackStr, gTokenUID ); 141 gTokenUID++; 142 hashPtr = Tcl_CreateHashEntry( callBackHashTablePtr, 143 tmpstr, &isNew ); 144 Tcl_SetHashValue( hashPtr, entryPtr ); 145 entryPtr->hashPtr = hashPtr; 146 Tcl_SetObjResult( interp, Tcl_NewStringObj( tmpstr, -1 ) ); 147 break; 148 } 149 150 case kCallBackCmdCancel: { 151 hashPtr = Tcl_FindHashEntry( callBackHashTablePtr, 152 Tcl_GetString( objv[1] ) ); 153 if (hashPtr == NULL) { 154 Tcl_SetObjResult( interp, Tcl_NewStringObj( 155 "Unrecognized callback token", -1 ) ); 156 return TCL_ERROR; 157 } 158 entryPtr = (CallBackEntry *) Tcl_GetHashValue( hashPtr ); 159 CancelCallBack( entryPtr->callback ); 160 DisposeCallBack( entryPtr->callback ); 161 Tcl_DeleteHashEntry( hashPtr ); 162 ckfree( (char *) entryPtr ); 163 break; 164 } 165 166 case kCallBackCmdInfo: { 167 if (callBackHashTablePtr == NULL) { 168 return TCL_OK; 169 } 170 if (objc == 1) { 171 172 /* 173 * Return a list of all tokens. 174 */ 175 176 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 177 hashPtr = Tcl_FirstHashEntry( callBackHashTablePtr, &search ); 178 while (hashPtr != NULL) { 179 entryPtr = (CallBackEntry *) Tcl_GetHashValue( hashPtr ); 180 objPtr = Tcl_NewStringObj( gTokenCallbackStr, -1 ); 181 Tcl_AppendObjToObj( objPtr, Tcl_NewIntObj( entryPtr->uid ) ); 182 Tcl_ListObjAppendElement( interp, listObjPtr, objPtr ); 183 hashPtr = Tcl_NextHashEntry( &search ); 184 } 185 Tcl_SetObjResult( interp, listObjPtr ); 186 187 } else if (objc == 2) { 188 189 /* 190 * Return detailed info on this particular callback token. 191 */ 192 193 hashPtr = Tcl_FindHashEntry( callBackHashTablePtr, 194 Tcl_GetString( objv[1] ) ); 195 if (hashPtr == NULL) { 196 Tcl_SetObjResult( interp, Tcl_NewStringObj( 197 "Unrecognized callback token", -1 ) ); 198 return TCL_ERROR; 199 } 200 entryPtr = (CallBackEntry *) Tcl_GetHashValue( hashPtr ); 201 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 202 Tcl_ListObjAppendElement( interp, listObjPtr, entryPtr->cmdObjPtr ); 203 Tcl_ListObjAppendElement( interp, listObjPtr, 204 Tcl_NewLongObj( entryPtr->movTime ) ); 205 Tcl_SetObjResult( interp, listObjPtr ); 206 207 } else { 208 Tcl_WrongNumArgs( interp, 0, objv, 209 "pathName callback info ?callbacktoken?" ); 210 return TCL_ERROR; 211 } 212 break; 213 } 214 } 215 216 return result; 217} 218 219/* 220 *---------------------------------------------------------------------- 221 * 222 * CallBackProc -- 223 * 224 * Called from QuickTime when time event to invoke the registered 225 * Tcl procedure. 226 * 227 * Results: 228 * None. 229 * 230 * Side effects: 231 * Invokes Tcl procedure. 232 * 233 *---------------------------------------------------------------------- 234 */ 235 236pascal void 237CallBackProc( QTCallBack cb, long refCon ) 238{ 239 CallBackEntry *entryPtr = (CallBackEntry *) refCon; 240 Tcl_Interp *interp = entryPtr->movPtr->interp; 241 int i; 242 int result = TCL_OK; 243 Tcl_Obj *objv[4]; 244 245 objv[0] = entryPtr->cmdObjPtr; 246 objv[1] = Tcl_NewStringObj( gTokenCallbackStr, -1 ); 247 Tcl_AppendObjToObj( objv[1], Tcl_NewIntObj( entryPtr->uid ) ); 248 objv[2] = Tcl_NewStringObj( Tk_PathName(entryPtr->movPtr->tkwin), -1 ); 249 objv[3] = Tcl_NewLongObj( entryPtr->movTime ); 250 for (i = 0; i < 4; i++) { 251 Tcl_IncrRefCount( objv[i] ); 252 } 253 Tcl_Preserve( (ClientData) entryPtr ); 254 result = Tcl_EvalObjv( interp, 4, objv, 0 ); 255 Tcl_Release( (ClientData) entryPtr ); 256 for (i = 0; i < 4; i++) { 257 Tcl_DecrRefCount( objv[i] ); 258 } 259 Tcl_DecrRefCount( entryPtr->cmdObjPtr ); 260 261 /* 262 * One shot callback; remove from our hash table since used. 263 */ 264 265 if (entryPtr->hashPtr != NULL) { 266 Tcl_DeleteHashEntry( entryPtr->hashPtr ); 267 } 268 ckfree( (char *) entryPtr ); 269} 270 271/* 272 *---------------------------------------------------------------------- 273 * 274 * CallBackFree -- 275 * 276 * Called when destroying movie to free up hash table for this specific 277 * instance. Assume the QT callbacks are destroyed with the movie itself. 278 * 279 * Results: 280 * None. 281 * 282 * Side effects: 283 * Frees memory. 284 * 285 *---------------------------------------------------------------------- 286 */ 287 288void 289CallBackFree( MoviePlayer *movPtr ) 290{ 291 Tcl_HashTable *callBackHashTablePtr = movPtr->callBackHashTablePtr; 292 Tcl_HashEntry *hPtr; 293 Tcl_HashSearch search; 294 CallBackEntry *entryPtr; 295 296 if (callBackHashTablePtr != NULL) { 297 hPtr = Tcl_FirstHashEntry( callBackHashTablePtr, &search ); 298 while (hPtr != NULL) { 299 entryPtr = (CallBackEntry *) Tcl_GetHashValue( hPtr ); 300 Tcl_DecrRefCount( entryPtr->cmdObjPtr ); 301 Tcl_DeleteHashEntry( hPtr ); 302 ckfree( (char *) entryPtr ); 303 hPtr = Tcl_NextHashEntry( &search ); 304 } 305 } 306} 307 308/*---------------------------------------------------------------------------*/ 309