1/* 2 * MoviePlayer.c -- 3 * 4 * QuickTime Movie widget for Tcl/Tk, part of QuickTimeTcl. 5 * 6 * Copyright (c) 1998 Bruce O'Neel 7 * Copyright (c) 2000-2008 Mats Bengtsson 8 * 9 * $Id: MoviePlayer.c,v 1.31 2008/04/29 13:11:31 matben Exp $ 10 */ 11 12#include "MoviePlayer.h" 13 14/* 15 * Used for controller timer callback. Presently unused. 16 */ 17 18typedef struct ControllerTimerRecord { 19 MoviePlayer *movPtr; 20 char *tclCmd; 21} ControllerTimerRecord; 22 23TrackScrap gTrackScrap; 24 25/* 26 * Record to handle callbacks to scripy level when async movie loading (-url). 27 */ 28 29typedef struct AsyncLoadHandlerEntry { 30 MoviePlayer *movPtr; 31 Tcl_TimerToken timerToken; /* Tcl's token for the timer handler. */ 32 Tcl_Obj *commandObjPtr; /* Command to invoke when the 33 * handler is invoked. */ 34 Tcl_HashEntry *hashPtr; /* Self referencing; useful when freeing */ 35} AsyncLoadHandlerEntry; 36 37static GWorldPtr gOffscreenGWorldPtr = NULL; 38 39 40/* 41 * We need a global doubly linked list for our movies since we cant get them 42 * to the Mac native event handler in any other way. 43 */ 44 45static MoviePlayerList *gMoviePlayerListPtr = NULL; 46 47/* 48 * Need to keep a ref count on how many movies actually opened. 49 * Different from 'MoviePlayerList' since movie "eventually" disposed. 50 */ 51 52static int gMovieRefCount = 0; 53 54/* 55 * Time interval for Carbon event timer (in secs). Apple recommendation. 56 */ 57 58#if TARGET_API_MAC_CARBON 59 60EventLoopTimerRef gCarbonMovieTimerRef = NULL; 61const EventTime kCarbonMovieTimerSecs = kEventDurationSecond / 10; 62long kMinimumIdleDurationInMillis = 20; 63 64/* 65 * Hash table to keep track of Carbon window event handlers. 66 * It maps a WindowRef (WindowPtr) to its corresponding event handler. 67 */ 68 69static Tcl_HashTable *gCarbonWindowHandlerHashPtr = NULL; 70 71typedef struct CarbonWindowHandlerEntry { 72 EventHandlerRef handlerRef; 73 long refCount; /* Number of movies in this window. */ 74} CarbonWindowHandlerEntry; 75 76#endif 77 78/* 79 * We need a global variable to set if either or both of MoviePlayer or 80 * SeqGrabber is running. This is used by our common Mac event procedure to 81 * figure out if we should call MoviePlayerMacEvent and/or SeqGrabberMacEvent. 82 * It is declared external in SeqGrabber.c. 83 */ 84 85long gIsRunningFlags = 0L; 86 87/* 88 * Keeps track of freeing things in correct order when closing down. 89 */ 90static enum QTTclFreeState gExitState = 0; 91 92static Boolean gHasQTVRManager = false; 93 94/* 95 * For dispatching movie commands. Order!!! 96 */ 97 98static char *allMovieCmds[] = { 99 "add", 100 "callback", 101 "cget", 102 "clear", 103 "compress", 104 "configure", 105 "controllerinfo", 106 "copy", 107 "cut", 108 "effect", 109 "export", 110 "fieldofview", 111 "flatten", 112 "getpreferredrate", 113 "getrate", 114 "getselection", 115 "gettime", 116 "haschanged", 117 "hotspot", 118 "isdone", 119 "ismovie", 120 "ispanoramic", 121 "isscrapmovie", 122 "isvisual", 123 "new", 124 "nextinterestingtime", 125 "pan", 126 "panoinfo", 127 "paste", 128 "picture", 129 "play", 130 "playhints", 131 "rate", 132 "save", 133 "saveas", 134 "select", 135 "setpreferredrate", 136 "setrate", 137 "settime", 138 "size", 139 "step", 140 "stop", 141 "tilt", 142 "time", 143 "timecode", 144 "tracks", 145 "undo", 146 "userdata", 147 (char *) NULL 148}; 149 150enum { 151 kMovieCmdAdd = 0L, 152 kMovieCmdCallBack, 153 kMovieCmdCget, 154 kMovieCmdClear, 155 kMovieCmdCompress, 156 kMovieCmdConfigure, 157 kMovieCmdControllerinfo, 158 kMovieCmdCopy, 159 kMovieCmdCut, 160 kMovieCmdEffect, 161 kMovieCmdExport, 162 kMovieCmdFieldofview, 163 kMovieCmdFlatten, 164 kMovieCmdGetpreferredrate, 165 kMovieCmdGetrate, 166 kMovieCmdGetselection, 167 kMovieCmdGettime, 168 kMovieCmdHasChanged, 169 kMovieCmdHotspot, 170 kMovieCmdIsdone, 171 kMovieCmdIsmovie, 172 kMovieCmdIspanoramic, 173 kMovieCmdIsscrapmovie, 174 kMovieCmdIsvisual, 175 kMovieCmdNew, 176 kMovieCmdNextInterestingTime, 177 kMovieCmdPan, 178 kMovieCmdPanoInfo, 179 kMovieCmdPaste, 180 kMovieCmdPicture, 181 kMovieCmdPlay, 182 kMovieCmdPlayHints, 183 kMovieCmdRate, 184 kMovieCmdSave, 185 kMovieCmdSaveas, 186 kMovieCmdSelect, 187 kMovieCmdSetpreferredrate, 188 kMovieCmdSetrate, 189 kMovieCmdSettime, 190 kMovieCmdSize, 191 kMovieCmdStep, 192 kMovieCmdStop, 193 kMovieCmdTilt, 194 kMovieCmdTime, 195 kMovieCmdTimeCode, 196 kMovieCmdTracks, 197 kMovieCmdUndo, 198 kMovieCmdUserData, 199 kMovieCmdUndocumeted1, 200 kMovieCmdUndocumeted2 201}; 202 203static char *allMovieFlattenOpts[] = { 204 "-dialog", "-dontinterleave", "-forceresourcebeforedata", 205 (char *) NULL 206}; 207 208enum { 209 kMovieFlattenOptDialog = 0L, 210 kMovieFlattenOptDontInterleave, 211 kMovieFlattenOptForceResourceBeforeData 212}; 213 214static char *allMoviePlayHintsOpts[] = { 215 "-scrubmode", 216 "-usesoundinterp", 217 "-allowinterlace", 218 "-allowblacklining", 219 "-dontpurge", 220 "-inactive", 221 "-highquality", 222 (char *) NULL 223}; 224 225enum { 226 kMoviePlayHintsOptScrubMode = 0L, 227 kMoviePlayHintsOptUseSoundInterp, 228 kMoviePlayHintsOptAllowInterlace, 229 kMoviePlayHintsOptAllowBlacklining, 230 kMoviePlayHintsOptDontPurge, 231 kMoviePlayHintsOptInactive, 232 kMoviePlayHintsOptHighQuality 233}; 234 235static Tk_ClassProcs MoviePlayerProcs = { 236 sizeof(Tk_ClassProcs), 237 MoviePlayerWorldChanged, /* geometryProc */ 238 NULL, /* createProc */ 239 NULL /* modalproc */ 240}; 241 242/* 243 * Information used for parsing configuration options. 244 * Mask bits for options changed. 245 */ 246 247enum { 248 MOV_CONF_NEWGWORLD = (1L << 0), 249 MOV_CONF_FILE = (1L << 1), 250 MOV_CONF_URL = (1L << 2), 251 MOV_CONF_MCEDIT = (1L << 3), 252 MOV_CONF_LOOPSTATE = (1L << 4), 253 MOV_CONF_PALINDROME_LOOPSTATE = (1L << 5), 254 MOV_CONF_VOLUME = (1L << 6), 255 MOV_CONF_PREFERRED_RATE = (1L << 7), 256 MOV_CONF_QTVR_QUALITY_STATIC = (1L << 8), 257 MOV_CONF_QTVR_QUALITY_MOTION = (1L << 9), 258 MOV_CONF_LOAD_INTO_RAM = (1L << 10), 259 MOV_CONF_PROGRESS_PROC = (1L << 11), 260 MOV_CONF_CUSTOM_BUTTON = (1L << 12), 261 MOV_CONF_RESIZEABLE = (1L << 13), 262 MOV_CONF_HIGHLIGHTS = (1L << 14) 263}; 264 265/* 266 * The following table defines the legal values for the -qtvrqualitystatic option. 267 */ 268 269static CONST char *kQTVRQualityArr[] = { 270 "min", "low", "normal", "high", "max", (char *) NULL 271}; 272#define MOV_QTVR_QUALITY_MIN 0 273#define MOV_QTVR_QUALITY_LOW 1 274#define MOV_QTVR_QUALITY_NORMAL 2 275#define MOV_QTVR_QUALITY_HIGH 3 276#define MOV_QTVR_QUALITY_MAX 4 277 278#define BLACK "Black" 279#define WHITE "White" 280 281#if TARGET_API_MAC_CARBON 282#define NORMAL_BG "systemWindowBody" 283#endif 284#ifdef _WIN32 285#define NORMAL_BG "SystemButtonFace" 286#endif 287 288 289static Tk_OptionSpec MoviePlayerConfigSpecs[] = { 290 {TK_OPTION_BOOLEAN, "-controller", "controller", "Controller", 291 "1", -1, Tk_Offset(MoviePlayer, wantController), 0, 292 (ClientData) NULL, 0}, 293 {TK_OPTION_BOOLEAN, "-custombutton", "customButton", "CustomButton", 294 "0", -1, Tk_Offset(MoviePlayer, custombutton), 0, 295 (ClientData) NULL, MOV_CONF_CUSTOM_BUTTON}, 296 {TK_OPTION_STRING, "-file", "file", "File", 297 NULL, Tk_Offset(MoviePlayer, fileNamePtr), -1, TK_OPTION_NULL_OK, 298 (ClientData) NULL, MOV_CONF_FILE}, 299 {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground", "HighlightBackground", 300 NORMAL_BG, -1, Tk_Offset(MoviePlayer, highlightBgColorPtr), 0, 0, MOV_CONF_HIGHLIGHTS}, 301 {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor", 302 BLACK, -1, Tk_Offset(MoviePlayer, highlightColorPtr), 0, 0, MOV_CONF_HIGHLIGHTS}, 303 {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness", "HighlightThickness", 304 "0", -1, Tk_Offset(MoviePlayer, highlightWidth), 0, 0, MOV_CONF_HIGHLIGHTS}, 305 {TK_OPTION_PIXELS, "-height", "height", "Height", 306 "0", -1, Tk_Offset(MoviePlayer, height), 0, 307 (ClientData) NULL, MOV_CONF_NEWGWORLD}, 308 {TK_OPTION_STRING, "-loadcommand", "loadCommand", "LoadCommand", 309 NULL, -1, Tk_Offset(MoviePlayer, loadCommand), TK_OPTION_NULL_OK, 310 (ClientData) NULL, 0}, 311 {TK_OPTION_BOOLEAN, "-loadintoram", "loadIntoRam", "LoadIntoRam", 312 "0", -1, Tk_Offset(MoviePlayer, loadIntoRam), 0, 313 (ClientData) NULL, MOV_CONF_LOAD_INTO_RAM}, 314 {TK_OPTION_BOOLEAN, "-loopstate", "loopstate", "Loopstate", 315 "0", -1, Tk_Offset(MoviePlayer, loopstate), 0, 316 (ClientData) NULL, MOV_CONF_LOOPSTATE}, 317 {TK_OPTION_STRING, "-mccommand", "mcCommand", "MCCommand", 318 NULL, -1, Tk_Offset(MoviePlayer, mcCallbackProc), TK_OPTION_NULL_OK, 319 (ClientData) NULL, 0}, 320 {TK_OPTION_BOOLEAN, "-mcedit", "mcEdit", "MCEdit", 321 "0", -1, Tk_Offset(MoviePlayer, mcEdit), 0, 322 (ClientData) NULL, MOV_CONF_MCEDIT}, 323 {TK_OPTION_BOOLEAN, "-palindromeloopstate", "palindromeLoopstate", "PalindromeLoopstate", 324 "0", -1, Tk_Offset(MoviePlayer, palindromeloopstate), 0, 325 (ClientData) NULL, MOV_CONF_PALINDROME_LOOPSTATE}, 326 {TK_OPTION_DOUBLE, "-preferredrate", "preferredRate", "PreferredRate", 327 "1.0", -1, Tk_Offset(MoviePlayer, preferredRate), 0, 328 (ClientData) NULL, MOV_CONF_PREFERRED_RATE}, 329 {TK_OPTION_STRING, "-progressproc", "progressProc", "ProgressProc", 330 NULL, -1, Tk_Offset(MoviePlayer, progressProc), TK_OPTION_NULL_OK, 331 (ClientData) NULL, MOV_CONF_PROGRESS_PROC}, 332 {TK_OPTION_BOOLEAN, "-qtprogress", "qtProgress", "QTProgress", 333 "1", -1, Tk_Offset(MoviePlayer, qtprogress), 0, 334 (ClientData) NULL, MOV_CONF_PROGRESS_PROC}, 335 {TK_OPTION_STRING_TABLE, "-qtvrqualitystatic", "qtvrQualityStatic", "QTVRQualityStatic", 336 "normal", -1, Tk_Offset(MoviePlayer, indQTVRQualityStatic), 0, 337 (ClientData) kQTVRQualityArr, MOV_CONF_QTVR_QUALITY_STATIC}, 338 {TK_OPTION_STRING_TABLE, "-qtvrqualitymotion", "qtvrQualityMotion", "QTVRQualityMotion", 339 "normal", -1, Tk_Offset(MoviePlayer, indQTVRQualityMotion), 0, 340 (ClientData) kQTVRQualityArr, MOV_CONF_QTVR_QUALITY_MOTION}, 341 {TK_OPTION_BOOLEAN, "-resizable", "resizable", "Resizable", 342 "0", -1, Tk_Offset(MoviePlayer, resizable), 0, 343 (ClientData) NULL, MOV_CONF_RESIZEABLE}, 344 {TK_OPTION_BOOLEAN, "-swing", "swing", "Swing", 345 "0", -1, Tk_Offset(MoviePlayer, swing), 0, 346 (ClientData) NULL, 0}, 347 {TK_OPTION_INT, "-swingspeed", "swingSpeed", "SwingSpeed", 348 "5", -1, Tk_Offset(MoviePlayer,swingSpeed), 0, 349 (ClientData) NULL, 0}, 350 {TK_OPTION_STRING, "-url", "url", "Url", 351 NULL, -1, Tk_Offset(MoviePlayer, url), TK_OPTION_NULL_OK, 352 (ClientData) NULL, MOV_CONF_URL}, 353 {TK_OPTION_INT, "-volume", "volume", "Volume", 354 "255", -1, Tk_Offset(MoviePlayer, volume), 0, 355 (ClientData) NULL, MOV_CONF_VOLUME}, 356 {TK_OPTION_PIXELS, "-width", "width", "Width", 357 "0", -1, Tk_Offset(MoviePlayer, width), 0, 358 (ClientData) NULL, MOV_CONF_NEWGWORLD}, 359 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL, 360 (char *) NULL, 0, 0, 0, 0} 361}; 362 363/* 364 * Declarations for functions in this source file only. 365 */ 366 367static int MoviePlayerWidgetCmd( ClientData clientData, 368 Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ); 369static MoviePlayer *CreateMoviePlayer( Tk_Window tkwin ); 370static int ConfigureMoviePlayer( Tcl_Interp *interp, 371 MoviePlayer *movPtr, int objc, Tcl_Obj *CONST objv[] ); 372static int ConfigureQTVRMovie( Tcl_Interp *interp, 373 MoviePlayer * movPtr, int setQTVRQualityStatic, 374 int setQTVRQualityMotion ); 375static int GetMovie( MoviePlayer *movPtr ); 376static int GetMovieFromUrl( MoviePlayer *movPtr ); 377static void MoviePlayerDeletedProc( ClientData clientData ); 378static void MoviePlayerEventProc( ClientData clientData, 379 XEvent *eventPtr ); 380static void AddOrRemoveMovieController( MoviePlayer *movPtr ); 381static void AddMovieToOpenMovies( MoviePlayer *movPtr ); 382static void RemoveMovieFromOpenMovies( MoviePlayer *movPtr ); 383static void DisplayMovie( ClientData clientData ); 384static void DestroyMovie( MoviePlayer *movPtr ); 385static void MoviePlayerFree( char *clientData ); 386static void DisposeMovieAtIdle( ClientData clientData ); 387static void MovieExitProc( ClientData clientData ); 388static void ExitMoviePlayer( ClientData clientData ); 389static void CheckMovieLoadState( MoviePlayer *movPtr ); 390static int MoviePlayerMacEvent( EventRecord *eventPtr, 391 WindowRef serveWindowRef ); 392#ifdef _WIN32 393static int MoviePlayerMacEventWin( EventRecord *eventPtr ); 394#endif 395static int ProcessVectorSubcmd( ClientData clientData, 396 Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ); 397static int ProcessSpriteSubcmd( ClientData clientData, 398 Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ); 399static pascal Boolean MovieControllerCallbackFunction( MovieController mc, 400 short action, void *params, long refCon ); 401static void InstallExtendedSCCallbackProcedures( 402 ComponentInstance ci, long refCon ); 403static pascal Boolean MySCFilterDialogProc( DialogPtr dialogPtr, 404 EventRecord * event, short *itemHit, long refCon ); 405static pascal OSErr MovieProgressFunction( Movie theMovie, short message, 406 short whatOperation, Fixed percentDone, long refcon ); 407static void ControllerCallbackTimer( ClientData clientData ); 408 409static int ComressMovieCmd(Tcl_Interp *interp, 410 int objc, Tcl_Obj *CONST objv[], 411 MoviePlayer *movPtr); 412static int NewMovieCmd(Tcl_Interp *interp, 413 int objc, Tcl_Obj *CONST objv[], 414 MoviePlayer *movPtr); 415static int FlattenMovieCmd(Tcl_Interp *interp, 416 int objc, Tcl_Obj *CONST objv[], 417 MoviePlayer *movPtr); 418 419static void AsyncLoadHandlerProc( ClientData clientData ); 420static void AsyncLoadFree( MoviePlayer *movPtr ); 421 422#if TARGET_OS_MAC 423static void SetMoviePlayerRectBox( MoviePlayer *movPtr ); 424#endif 425 426#if TARGET_API_MAC_CARBON 427static pascal void MoviePlayerCarbonTimer( EventLoopTimerRef theTimer, 428 void *userData ); 429static OSStatus InstallMovieIdlingEventLoopTimer( void ); 430static void TaskNeededSoonerCallback( TimeValue duration, 431 unsigned long flags, void *refcon ); 432static void CarbonTimerNextTime( void ); 433static void InstallCarbonWindowEventHandler( MoviePlayer *movPtr ); 434static OSStatus MovieCarbonWindowEventHandler( EventHandlerCallRef callRef, 435 EventRef eventRef, void *userData ); 436static void MovieDestroyCarbonWindowHandlerCleanup( MoviePlayer *movPtr ); 437#endif 438 439#ifdef _WIN32 440LRESULT CALLBACK QTWinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ); 441#endif 442 443/* 444 *---------------------------------------------------------------------- 445 * 446 * MoviePlayerObjCmd -- 447 * 448 * Create a MoviePlayer widget. 449 * 450 * Results: 451 * Standard TCL result 452 * 453 * Side effects: 454 * Creates a command and allocates memory. Possibly allocates 455 * mac structures INITS the Movie toolbox, this could conflict 456 * with someone else 457 * 458 *---------------------------------------------------------------------- 459 */ 460 461int 462MoviePlayerObjCmd( 463 ClientData clientData, /* NULL */ 464 Tcl_Interp *interp, 465 int objc, 466 Tcl_Obj *CONST objv[] ) 467{ 468 MoviePlayer *movPtr; 469 Tk_Window tkwin; 470 Tk_OptionTable optionTable; 471 long gestalt; 472 long eventFlags = 0; 473 static int enterMoviesCalled = 0; 474 OSErr err = noErr; 475 Rect aRect = { 0, 0, 10, 10 }; /* Just a dummy rect. */ 476 477 if (noErr != Gestalt( gestaltQuickTime, &gestalt )) { 478 Tcl_SetObjResult( interp, Tcl_NewStringObj( "QuickTime not installed", -1 ) ); 479 return TCL_ERROR; 480 } 481 QTTclDebugPrintf( interp, 2, "MoviePlayerObjCmd" ); 482 483 /* 484 * Init QuickTime movies. 485 */ 486 487 if (!enterMoviesCalled) { 488 long attr; 489 490 err = EnterMovies(); 491 if (err != noErr) { 492 CheckAndSetErrorResult( interp, err ); 493 return TCL_ERROR; 494 } 495 enterMoviesCalled++; 496 gIsRunningFlags |= MOVIE_PLAYER_RUNS; 497 gTrackScrap.movPtr = NULL; 498 Tcl_CreateExitHandler( MovieExitProc, (ClientData) NULL ); 499 500 /* 501 * We use one and the same offscreen GWorld for all movies. 502 */ 503 504 err = MySafeNewGWorld( &gOffscreenGWorldPtr, 32, &aRect, NULL, NULL, 0 ); 505 if (err != noErr) { 506 CheckAndSetErrorResult( interp, err ); 507 return TCL_ERROR; 508 } 509 510 /* 511 * Check the availablity of the QTVR manager. 512 */ 513 514 gHasQTVRManager = false; 515 if (noErr == Gestalt( gestaltQTVRMgrAttr, &attr )) { 516 if (attr & (1 << gestaltQTVRMgrPresent)) { 517 gHasQTVRManager = true; 518 } 519 } 520 521 /* 522 * The video effects record needs to be inited. 523 */ 524 525 EffectsInit(); 526 527 QTTclDebugPrintf( interp, 2, "KeyPress=%2d KeyRelease=%2d ButtonPress=%2d ButtonRelease=%2d", 528 KeyPress, KeyRelease, ButtonPress, ButtonRelease ); 529 QTTclDebugPrintf( interp, 2, "FocusIn=%2d FocusOut=%2d Expose=%2d DestroyNotify=%2d UnmapNotify=%2d MapNotify=%2d ConfigureNotify=%2d", 530 FocusIn, FocusOut, Expose, DestroyNotify, UnmapNotify, MapNotify, ConfigureNotify ); 531 QTTclDebugPrintf( interp, 3, "\tgOffscreenGWorldPtr=0x%.8x", gOffscreenGWorldPtr ); 532 QTTclDebugPrintf( interp, 3, 533 "\tREDRAW_PENDING=%d, NEWGWORLD=%d, UPDATEMOVIE=%d", 534 REDRAW_PENDING, NEWGWORLD, UPDATEMOVIE ); 535 } 536 537 if (objc < 2) { 538 Tcl_WrongNumArgs( interp, 1, objv, "pathName ?options?" ); 539 return TCL_ERROR; 540 } 541 tkwin = Tk_CreateWindowFromPath( interp, Tk_MainWindow(interp), 542 Tcl_GetString(objv[1]), (char *) NULL ); 543 if (tkwin == NULL) { 544 return TCL_ERROR; 545 } 546 547 /* 548 * Create the option table for this widget class. If it has already 549 * been created, the cached pointer will be returned. 550 */ 551 552 optionTable = Tk_CreateOptionTable( interp, MoviePlayerConfigSpecs ); 553 554 Tk_SetClass( tkwin, "Movie" ); 555 movPtr = CreateMoviePlayer( tkwin ); 556 557 Tk_SetClassProcs( tkwin, &MoviePlayerProcs, (ClientData) movPtr ); 558 movPtr->tkwin = tkwin; 559 movPtr->display = Tk_Display( tkwin ); 560 movPtr->interp = interp; 561 movPtr->widgetCmd = Tcl_CreateObjCommand( interp, Tk_PathName(movPtr->tkwin), 562 MoviePlayerWidgetCmd, (ClientData) movPtr, MoviePlayerDeletedProc ); 563 movPtr->optionTable = optionTable; 564 565 /* 566 * Movie Player specific attributes. 567 */ 568 569 movPtr->aMovie = NULL; 570 movPtr->filename = NULL; 571 movPtr->fileNamePtr = NULL; 572 movPtr->url = NULL; 573 movPtr->flags = 0; 574 movPtr->state = 0; 575 movPtr->width = 0; 576 movPtr->height = 0; 577 movPtr->mheight = 0; 578 movPtr->mwidth = 0; 579 movPtr->padx = 0; 580 movPtr->pady = 0; 581 movPtr->highlightWidth = 0; 582 movPtr->inset = movPtr->padx + movPtr->highlightWidth; 583 movPtr->volume = 255; 584 movPtr->isVisual = 1; 585 movPtr->undoCount = 0; 586 movPtr->editStates = NULL; 587 movPtr->editStatesSize = 0; 588 movPtr->loadIntoRam = 0; 589 movPtr->qtvrInstance = NULL; 590 movPtr->indQTVRQualityStatic = -1; 591 movPtr->indQTVRQualityMotion = -1; 592 movPtr->funcQTVRIntercept = NULL; 593 movPtr->swing = 0; 594 movPtr->swingSpeed = 5; 595 movPtr->trackSelect->trackID = 0; 596 597 /* A resource number -1 means movie in data fork. */ 598 movPtr->resourceNumber = -1; 599 movPtr->progressProc = NULL; 600 movPtr->grafPtr = NULL; 601 movPtr->qtprogress = 1; 602 movPtr->mcCallbackProc = NULL; 603 movPtr->loadCommand = NULL; 604 movPtr->loadState = 0; 605 movPtr->aController = NULL; 606 movPtr->wantController = 1; 607 movPtr->controllerHeight = 0; 608 movPtr->mcEdit = 0; 609 movPtr->resizable = 0; 610 movPtr->custombutton = 0; 611 movPtr->loopstate = 0; 612 movPtr->palindromeloopstate = 0; 613 movPtr->rate = (Fixed) 0; 614 movPtr->preferredRate = 1.0; 615 movPtr->insideMCCommand = 0; 616 movPtr->asyncLoadHashTablePtr = NULL; 617 movPtr->callBackHashTablePtr = NULL; 618 movPtr->tmpMovieRecordPtr = NULL; 619 620 QTTclDebugPrintf( interp, 2, "\tmovPtr=%d", movPtr ); 621 622 /* 623 * This is an extremly important choice of which events shall be handled 624 * by tk. Using the ExposureMask seems to cause infinite loops, 625 * in particular when the controller is obscured. 626 */ 627 628#if TARGET_OS_MAC 629 eventFlags = StructureNotifyMask | FocusChangeMask | 630 VisibilityChangeMask | KeyReleaseMask | ButtonPressMask; 631#else 632 eventFlags = ExposureMask | StructureNotifyMask | FocusChangeMask | 633 VisibilityChangeMask | KeyReleaseMask | ButtonPressMask; 634#endif 635 Tk_CreateEventHandler( movPtr->tkwin, eventFlags, 636 MoviePlayerEventProc, (ClientData) movPtr ); 637 638 if (Tk_InitOptions( interp, (char *) movPtr, optionTable, movPtr->tkwin ) 639 != TCL_OK) { 640 Tk_DestroyWindow( movPtr->tkwin ); 641 return TCL_ERROR; 642 } 643 644 /* 645 * Configure the widget; parse the command line arguments and look for defaults 646 * in the resource database. The last 0 means to ... 647 */ 648 649 if (ConfigureMoviePlayer( interp, movPtr, objc - 2, objv + 2 ) 650 != TCL_OK) { 651 Tk_DestroyWindow( movPtr->tkwin ); 652 return TCL_ERROR; 653 } 654 655 /* 656 * Windows specific code to create a Mac style graphics port, and associate 657 * it with a Windows HWND. Get the winproc given by tk, save it to be called 658 * later, and set our own winproc. 659 */ 660 661#ifdef _WIN32 662 { 663 HWND tempHwnd = NULL; 664 665 if (Tk_WindowId(movPtr->tkwin) == None) { 666 Tk_MakeWindowExist( movPtr->tkwin ); 667 } 668 tempHwnd = TkWinGetHWND( Tk_WindowId(movPtr->tkwin) ); 669 movPtr->hwnd = tempHwnd; 670 CreatePortAssociation( tempHwnd, NULL, 0L ); 671 movPtr->winEventProc = GetWindowLong( tempHwnd, GWL_WNDPROC ); 672 SetWindowLong( tempHwnd, GWL_WNDPROC, (LONG) QTWinProc ); 673 } 674#endif // _WIN32 675 676 /* 677 * We should add our movie to our global list of open movies already here. 678 * This is mainly to get a handle on the original WndProc on Windows, so it 679 * can get called even if not widget on display. 680 */ 681 682 AddMovieToOpenMovies( movPtr ); 683 684 /* 685 * Set the NEWGWORLD in 'flags' to require an update and to find the geometry. 686 * If a remote movie is async loading, a 1x1 size is given in 'MoviePlayerWorldChanged'. 687 */ 688 689 movPtr->flags |= NEWGWORLD; 690 movPtr->flags |= NEED_PREROLL; 691 MoviePlayerWorldChanged( (ClientData) movPtr ); 692 Tcl_SetObjResult( interp, Tcl_NewStringObj( Tk_PathName(movPtr->tkwin), -1 ) ); 693 return TCL_OK; 694} 695/* 696 *---------------------------------------------------------------------- 697 * 698 * MoviePlayerWidgetCmd -- 699 * 700 * Command to run for each widget. 701 * 702 * Results: 703 * Normal TCL results 704 * 705 * Side effects: 706 * Memory allocated and/or freed, Mac Movie structures modified 707 * 708 *---------------------------------------------------------------------- 709 */ 710 711static int 712MoviePlayerWidgetCmd( ClientData clientData, 713 Tcl_Interp *interp, 714 int objc, 715 Tcl_Obj *CONST objv[] ) 716{ 717 MoviePlayer *movPtr = (MoviePlayer *) clientData; 718 Movie aMovie = movPtr->aMovie; 719 short resId; 720 short movieResFile; 721 unsigned short vol; 722 int i; 723 int undoLevel; 724 int sizeMayChange; 725 int iarg; 726 int cmdIndex; 727 int optIndex; 728 int boolValue; 729 int intValue; 730 long flags; 731 long mask; 732 long longValue; 733 double theRate; 734 Tcl_Obj *resultObjPtr; 735 Tcl_Obj *listObjPtr; 736 Fixed rate; 737 TimeValue movTime; 738 TimeValue movDuration; 739 FSSpec fss; 740 PicHandle thePic = NULL; 741 Movie tmpMovie = NULL; 742 OSErr err = noErr; 743 ComponentResult compErr = badComponentType; 744 int result = TCL_OK; 745 746 if (objc < 2) { 747 Tcl_WrongNumArgs( interp, 1, objv, "command ?arg arg ...?" ); 748 return TCL_ERROR; 749 } 750 QTTclDebugPrintf( interp, 2, "MoviePlayerWidgetCmd" ); 751 752 Tcl_Preserve((ClientData) movPtr); 753 if (Tcl_GetIndexFromObj( interp, objv[1], allMovieCmds, "command", TCL_EXACT, &cmdIndex ) 754 != TCL_OK ) { 755 return TCL_ERROR; 756 } 757 758 /* Get the volume since the user may have changed it. */ 759 760 vol = GetMovieVolume( aMovie ); 761 movPtr->volume = vol; 762 763 /* 764 * Dispatch the movie command to the right branch. 765 */ 766 767 switch (cmdIndex) { 768 769 case kMovieCmdAdd: { 770 771 /* 772 * Add tracks in parallel to the movie. 773 */ 774 775 if (objc >= 3) { 776 Tcl_WrongNumArgs( interp, 2, objv, NULL ); 777 result = TCL_ERROR; 778 goto error; 779 } 780 if (aMovie != NULL) { 781 tmpMovie = NewMovieFromScrap(0); 782 if (tmpMovie != NULL) { 783 result = LogUndoState( movPtr, interp ); 784 AddMovieSelection( aMovie, tmpMovie ); 785 /* // scales to fit... 786 GetMovieBox( tmpMovie, &aRect ); 787 MacOffsetRect( &aRect, -aRect.left, -aRect.top ); 788 if (aRect.right > movPtr->mwidth) { 789 movPtr->mwidth = aRect.right; 790 } 791 if (aRect.bottom > movPtr->mheight) { 792 movPtr->mheight = aRect.bottom; 793 } 794 */ 795 DisposeMovie( tmpMovie ); 796 } else { 797 CheckAndSetErrorResult( interp, noErr ); 798 result = TCL_ERROR; 799 } 800 if (movPtr->aController != NULL) { 801 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 802 MCMovieChanged( movPtr->aController, aMovie ); 803 } else { 804 MoviePlayerWorldChanged( clientData ); 805 } 806 } else { 807 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 808 result = TCL_ERROR; 809 } 810 break; 811 } 812 813 case kMovieCmdCallBack: { 814 if (objc < 3) { 815 Tcl_WrongNumArgs( interp, 2, objv, "time|cmd ?args?" ); 816 goto error; 817 } 818 if (aMovie != NULL) { 819 if (ProcessCallBackCmd( movPtr, objc-2, objv+2 ) != TCL_OK) { 820 result = TCL_ERROR; 821 } 822 } else { 823 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 824 result = TCL_ERROR; 825 } 826 break; 827 } 828 829 case kMovieCmdCget: { 830 831 /* 832 * Just return an option. 833 */ 834 835 if (objc != 3) { 836 Tcl_WrongNumArgs( interp, 2, objv, "option" ); 837 result = TCL_ERROR; 838 goto error; 839 } 840 resultObjPtr = Tk_GetOptionValue( interp, (char *) movPtr, 841 movPtr->optionTable, objv[2], movPtr->tkwin ); 842 if (resultObjPtr == NULL) { 843 result = TCL_ERROR; 844 } else { 845 Tcl_SetObjResult( interp, resultObjPtr ); 846 } 847 break; 848 } 849 850 case kMovieCmdClear: { 851 852 /* 853 * Clear any movie selection. 854 */ 855 856 if (objc != 2) { 857 Tcl_WrongNumArgs( interp, 2, objv, NULL ); 858 goto error; 859 } 860 if (aMovie != NULL) { 861 result = LogUndoState( movPtr, interp ); 862 if (movPtr->aController && MCIsEditingEnabled( movPtr->aController )) { 863 if (noErr != MCClear( movPtr->aController )) { 864 CheckAndSetErrorResult( interp, noErr ); 865 result = TCL_ERROR; 866 goto error; 867 } 868 } else { 869 ClearMovieSelection( aMovie ); 870 } 871 if (movPtr->aController != NULL) { 872 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 873 MCMovieChanged( movPtr->aController, aMovie ); 874 } else { 875 MoviePlayerWorldChanged( clientData ); 876 } 877 } else { 878 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 879 result = TCL_ERROR; 880 } 881 break; 882 } 883 884 case kMovieCmdConfigure: { 885 886 /* 887 * Configure an option. 888 */ 889 890 resultObjPtr = NULL; 891 if (objc <= 3) { 892 resultObjPtr = Tk_GetOptionInfo( interp, (char *) movPtr, 893 movPtr->optionTable, 894 (objc == 2) ? (Tcl_Obj *) NULL : objv[2], 895 movPtr->tkwin ); 896 if (resultObjPtr == NULL) { 897 result = TCL_ERROR; 898 } else { 899 Tcl_SetObjResult( interp, resultObjPtr ); 900 } 901 } else { 902 903 /* 904 * Configure the widget; parse the command line arguments and look for defaults 905 * in the resource database. 906 */ 907 908 result = ConfigureMoviePlayer( interp, movPtr, objc - 2, objv + 2 ); 909 910 /* 911 * Only if we made a configuration that needs a redisplay. 912 */ 913 914 if ((result == TCL_OK) && (movPtr->flags & NEWGWORLD)) { 915 MoviePlayerWorldChanged( (ClientData) movPtr ); 916 } 917 } 918 break; 919 } 920 921 case kMovieCmdCompress: { 922 923 /* 924 * Compress the movie. 925 */ 926 927 if (!Tk_IsMapped(movPtr->tkwin)) { 928 Tcl_SetObjResult( interp, Tcl_NewStringObj( "Movie must be displayed", -1 ) ); 929 result = TCL_ERROR; 930 goto error; 931 } 932 if (objc < 3) { 933 Tcl_WrongNumArgs( interp, 2, objv, "filename" ); 934 result = TCL_ERROR; 935 goto error; 936 } 937 result = ComressMovieCmd(interp, objc, objv, movPtr); 938 if (result != TCL_OK) { 939 goto error; 940 } 941 break; 942 } 943 944 case kMovieCmdControllerinfo: { 945 946 /* 947 * Gets info about the state of the movie controller. 948 */ 949 950 if (objc != 2) { 951 Tcl_WrongNumArgs( interp, 2, objv, NULL ); 952 result = TCL_ERROR; 953 goto error; 954 } 955 if (aMovie != NULL) { 956 if (movPtr->aController != NULL) { 957 958 MCGetControllerInfo( movPtr->aController, &flags ); 959 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 960 Tcl_ListObjAppendElement( interp, listObjPtr, 961 Tcl_NewStringObj("-undoavailable", -1) ); 962 Tcl_ListObjAppendElement( interp, listObjPtr, 963 Tcl_NewBooleanObj(flags & mcInfoUndoAvailable) ); 964 Tcl_ListObjAppendElement( interp, listObjPtr, 965 Tcl_NewStringObj("-cutavailable", -1) ); 966 Tcl_ListObjAppendElement( interp, listObjPtr, 967 Tcl_NewBooleanObj(flags & mcInfoCutAvailable) ); 968 Tcl_ListObjAppendElement( interp, listObjPtr, 969 Tcl_NewStringObj("-copyavailable", -1) ); 970 Tcl_ListObjAppendElement( interp, listObjPtr, 971 Tcl_NewBooleanObj(flags & mcInfoCopyAvailable) ); 972 Tcl_ListObjAppendElement( interp, listObjPtr, 973 Tcl_NewStringObj("-pasteavailable", -1) ); 974 Tcl_ListObjAppendElement( interp, listObjPtr, 975 Tcl_NewBooleanObj(flags & mcInfoPasteAvailable) ); 976 Tcl_ListObjAppendElement( interp, listObjPtr, 977 Tcl_NewStringObj("-clearavailable", -1) ); 978 Tcl_ListObjAppendElement( interp, listObjPtr, 979 Tcl_NewBooleanObj(flags & mcInfoClearAvailable) ); 980 Tcl_ListObjAppendElement( interp, listObjPtr, 981 Tcl_NewStringObj("-hassound", -1) ); 982 Tcl_ListObjAppendElement( interp, listObjPtr, 983 Tcl_NewBooleanObj(flags & mcInfoHasSound) ); 984 Tcl_ListObjAppendElement( interp, listObjPtr, 985 Tcl_NewStringObj("-isplaying", -1) ); 986 Tcl_ListObjAppendElement( interp, listObjPtr, 987 Tcl_NewBooleanObj(flags & mcInfoIsPlaying) ); 988 Tcl_ListObjAppendElement( interp, listObjPtr, 989 Tcl_NewStringObj("-islooping", -1) ); 990 Tcl_ListObjAppendElement( interp, listObjPtr, 991 Tcl_NewBooleanObj(flags & mcInfoIsLooping) ); 992 Tcl_ListObjAppendElement( interp, listObjPtr, 993 Tcl_NewStringObj("-isinpalindrome", -1) ); 994 Tcl_ListObjAppendElement( interp, listObjPtr, 995 Tcl_NewBooleanObj(flags & mcInfoIsInPalindrome) ); 996 Tcl_ListObjAppendElement( interp, listObjPtr, 997 Tcl_NewStringObj("-editingenebled", -1) ); 998 Tcl_ListObjAppendElement( interp, listObjPtr, 999 Tcl_NewBooleanObj(flags & mcInfoEditingEnabled) ); 1000 1001 Tcl_SetObjResult( interp, listObjPtr ); 1002 } else { 1003 Tcl_SetObjResult( interp, 1004 Tcl_NewStringObj( "No movie controller", -1 ) ); 1005 result = TCL_ERROR; 1006 } 1007 } else { 1008 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1009 result = TCL_ERROR; 1010 } 1011 break; 1012 } 1013 1014 case kMovieCmdCopy: { 1015 1016 /* 1017 * Copy the Movie selection. Any track scrap must be invalidated. 1018 */ 1019 1020 if (aMovie != NULL) { 1021 if (movPtr->aController && MCIsEditingEnabled( movPtr->aController )) { 1022 tmpMovie = MCCopy( movPtr->aController ); 1023 } else { 1024 tmpMovie = CopyMovieSelection( aMovie ); 1025 } 1026 if (tmpMovie != NULL) { 1027 PutMovieOnScrap( tmpMovie, 0 ); 1028 DisposeMovie( tmpMovie ); 1029 gTrackScrap.movPtr = NULL; 1030 } else { 1031 CheckAndSetErrorResult( interp, noErr ); 1032 } 1033 } else { 1034 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1035 result = TCL_ERROR; 1036 } 1037 break; 1038 } 1039 1040 case kMovieCmdCut: { 1041 1042 /* 1043 * Cut the Movie selection. Any track scrap must be invalidated. 1044 */ 1045 1046 if (aMovie != NULL) { 1047 result = LogUndoState( movPtr, interp ); 1048 if (movPtr->aController && MCIsEditingEnabled( movPtr->aController )) { 1049 tmpMovie = MCCut( movPtr->aController ); 1050 } else { 1051 tmpMovie = CutMovieSelection( aMovie ); 1052 } 1053 if (tmpMovie != NULL) { 1054 PutMovieOnScrap( tmpMovie, 0 ); 1055 DisposeMovie( tmpMovie ); 1056 gTrackScrap.movPtr = NULL; 1057 } else { 1058 CheckAndSetErrorResult( interp, noErr ); 1059 } 1060 if (movPtr->aController != NULL) { 1061 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 1062 MCMovieChanged( movPtr->aController, aMovie ); 1063 } 1064 } else { 1065 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1066 result = TCL_ERROR; 1067 } 1068 break; 1069 } 1070 1071 case kMovieCmdEffect: { 1072 1073 /* 1074 * Make an effect, from 0, 1, or 2 sources. Displays an effect dialog. 1075 */ 1076 1077#if TARGET_API_MAC_CARBON 1078 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No effects on Mac OS X yet", -1 ) ); 1079 result = TCL_ERROR; 1080 break; 1081#endif 1082 if (aMovie != NULL) { 1083 1084 /* Continues in 'EffectsRespondToDialogSelection'... */ 1085 if (ProcessEffectCmd( interp, movPtr, objc - 2, objv + 2 ) 1086 != TCL_OK) { 1087 result = TCL_ERROR; 1088 goto error; 1089 } 1090 } else { 1091 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1092 result = TCL_ERROR; 1093 } 1094 break; 1095 } 1096 1097 case kMovieCmdExport: { 1098 1099 /* 1100 * Export the Movie from a dialog. Return file path or empty. 1101 */ 1102 1103 if (Tcl_IsSafe( interp )) { 1104 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1105 "\"export\" not allowed in a safe interpreter", -1 ) ); 1106 result = TCL_ERROR; 1107 goto error; 1108 } 1109 if (!Tk_IsMapped(movPtr->tkwin)) { 1110 Tcl_SetObjResult( interp, Tcl_NewStringObj( "Movie must be displayed", -1 ) ); 1111 result = TCL_ERROR; 1112 goto error; 1113 } 1114 if (aMovie != NULL) { 1115 if (ProcessExportCmd( interp, aMovie, objc - 2, objv + 2 ) != TCL_OK) { 1116 result = TCL_ERROR; 1117 goto error; 1118 } 1119 } else { 1120 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1121 result = TCL_ERROR; 1122 } 1123 break; 1124 } 1125 1126 case kMovieCmdFieldofview: { 1127 1128 /* 1129 * Set or get fieldofview of QTVR pano. 1130 */ 1131 1132 if (objc > 3) { 1133 Tcl_WrongNumArgs( interp, 2, objv, "?fov?" ); 1134 result = TCL_ERROR; 1135 goto error; 1136 } 1137 if (!gHasQTVRManager) { 1138 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1139 "Couldn't find the QTVR manager on this system", -1 ) ); 1140 result = TCL_ERROR; 1141 goto error; 1142 } 1143 if (aMovie != NULL) { 1144 double fov; 1145 1146 if (movPtr->qtvrInstance == NULL) { 1147 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1148 "Couldn't identify this movie as a VR movie", -1 ) ); 1149 result = TCL_ERROR; 1150 goto error; 1151 } 1152 if (objc == 3) { 1153 if (Tcl_GetDoubleFromObj( interp, objv[2], &fov ) != TCL_OK) { 1154 Tcl_AddErrorInfo( interp, 1155 "\n (processing fieldofview command)" ); 1156 } else { 1157 ZoomInOrOutPanorama( movPtr->qtvrInstance, 0, (float) fov ); 1158 } 1159 } else { 1160 fov = QTVRGetFieldOfView( movPtr->qtvrInstance ); 1161 Tcl_SetObjResult( interp, Tcl_NewDoubleObj(fov) ); 1162 } 1163 } else { 1164 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1165 result = TCL_ERROR; 1166 } 1167 break; 1168 } 1169 1170 case kMovieCmdFlatten: { 1171 1172 /* 1173 * Flatten the movie into the datafork of a new file. 1174 * A separate mechanism is used for QTVR panos. 1175 */ 1176 1177 if (Tcl_IsSafe( interp )) { 1178 Tcl_SetObjResult( interp, 1179 Tcl_NewStringObj("\"flatten\" not allowed in a safe interpreter", -1) ); 1180 result = TCL_ERROR; 1181 goto error; 1182 } 1183 if (objc < 3) { 1184 Tcl_WrongNumArgs( interp, 2, objv, "fileName ?args?" ); 1185 result = TCL_ERROR; 1186 goto error; 1187 } 1188 if (aMovie == NULL) { 1189 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1190 result = TCL_ERROR; 1191 goto error; 1192 } 1193 result = FlattenMovieCmd(interp, objc, objv, movPtr); 1194 if (result != TCL_OK) { 1195 goto error; 1196 } 1197 break; 1198 } 1199 1200 case kMovieCmdGetrate: { 1201 1202 /* 1203 * Get the movie rate. Must be playing. Now obsolete! Use "rate" instead. 1204 */ 1205 1206 if (aMovie != NULL) { 1207 Tcl_SetObjResult( interp, Tcl_NewDoubleObj( 1208 Fix2X( GetMovieRate(aMovie) ) ) ); 1209 } else { 1210 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1211 result = TCL_ERROR; 1212 } 1213 break; 1214 } 1215 1216 case kMovieCmdGetpreferredrate: { 1217 1218 /* 1219 * Get the movie preferred rate. Need not be playing. Now obsolete! 1220 */ 1221 1222 if (aMovie != NULL) { 1223 Tcl_SetObjResult( interp, Tcl_NewDoubleObj( 1224 Fix2X( GetMoviePreferredRate(aMovie) ) ) ); 1225 } else { 1226 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1227 result = TCL_ERROR; 1228 } 1229 break; 1230 } 1231 1232 case kMovieCmdGetselection: { 1233 1234 /* 1235 * Get the movie selection. Now obsolete, use "select". 1236 */ 1237 1238 if (aMovie != NULL) { 1239 GetMovieSelection(aMovie, &movTime, &movDuration); 1240 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 1241 result = TCL_ERROR; 1242 } else { 1243 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 1244 Tcl_ListObjAppendElement( interp, listObjPtr, 1245 Tcl_NewStringObj("-selectionTime", -1) ); 1246 Tcl_ListObjAppendElement( interp, listObjPtr, 1247 Tcl_NewLongObj(movTime) ); 1248 Tcl_ListObjAppendElement( interp, listObjPtr, 1249 Tcl_NewStringObj("-selectionDuration", -1) ); 1250 Tcl_ListObjAppendElement( interp, listObjPtr, 1251 Tcl_NewLongObj(movDuration) ); 1252 Tcl_SetObjResult( interp, listObjPtr ); 1253 } 1254 } else { 1255 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1256 result = TCL_ERROR; 1257 } 1258 break; 1259 } 1260 1261 case kMovieCmdGettime: { 1262 1263 /* 1264 * Return the time elapsed for the movie. 1265 */ 1266 1267 if (aMovie != NULL) { 1268 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 1269 Tcl_ListObjAppendElement( interp, listObjPtr, 1270 Tcl_NewStringObj("-movietime", -1) ); 1271 Tcl_ListObjAppendElement( interp, listObjPtr, 1272 Tcl_NewLongObj(GetMovieTime( aMovie, NULL )) ); 1273 Tcl_ListObjAppendElement( interp, listObjPtr, 1274 Tcl_NewStringObj("-movieduration", -1) ); 1275 Tcl_ListObjAppendElement( interp, listObjPtr, 1276 Tcl_NewLongObj(GetMovieDuration( aMovie )) ); 1277 Tcl_ListObjAppendElement( interp, listObjPtr, 1278 Tcl_NewStringObj("-movietimescale", -1) ); 1279 Tcl_ListObjAppendElement( interp, listObjPtr, 1280 Tcl_NewLongObj(GetMovieTimeScale( aMovie )) ); 1281 Tcl_ListObjAppendElement( interp, listObjPtr, 1282 Tcl_NewStringObj("-postertime", -1) ); 1283 Tcl_ListObjAppendElement( interp, listObjPtr, 1284 Tcl_NewLongObj(GetMoviePosterTime( aMovie )) ); 1285 Tcl_SetObjResult( interp, listObjPtr ); 1286 } else { 1287 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1288 result = TCL_ERROR; 1289 } 1290 break; 1291 } 1292 1293 case kMovieCmdHasChanged: { 1294 1295 /* 1296 * Return true if we edited the movie after it has been saved. 1297 */ 1298 1299 if (aMovie != NULL) { 1300 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1301 HasMovieChanged( aMovie ) ? true : false) ); 1302 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 1303 result = TCL_ERROR; 1304 goto error; 1305 } 1306 } else { 1307 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1308 result = TCL_ERROR; 1309 } 1310 break; 1311 } 1312 1313 case kMovieCmdHotspot: { 1314 1315 /* 1316 * The hotspot sub command. 1317 */ 1318 1319 if (aMovie != NULL) { 1320 if (IsQTVRMovie( aMovie ) && (movPtr->qtvrInstance != NULL)) { 1321 if (TCL_OK != ProcessHotspotSubCmd( interp, aMovie, 1322 movPtr->qtvrInstance, objc - 2, objv + 2 )) { 1323 result = TCL_ERROR; 1324 } 1325 } else { 1326 Tcl_SetObjResult( interp, Tcl_NewStringObj( "Not a QTVR movie", -1 ) ); 1327 result = TCL_ERROR; 1328 } 1329 } else { 1330 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1331 result = TCL_ERROR; 1332 } 1333 break; 1334 } 1335 1336 case kMovieCmdIsdone: { 1337 1338 /* 1339 * Is the movie done? 1340 */ 1341 1342 if (aMovie != NULL) { 1343 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1344 IsMovieDone( aMovie ) ? true : false) ); 1345 } else { 1346 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1347 result = TCL_ERROR; 1348 } 1349 break; 1350 } 1351 1352 case kMovieCmdIsmovie: { 1353 1354 /* 1355 * Is the movie an ordinary movie and not a VR panoramic movie? 1356 */ 1357 1358 if (aMovie != NULL) { 1359 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1360 IsQTVRMovie( aMovie ) ? false : true) ); 1361 } else { 1362 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1363 result = TCL_ERROR; 1364 } 1365 break; 1366 } 1367 1368 case kMovieCmdIspanoramic: { 1369 1370 /* 1371 * Is the movie a VR panoramic movie? 1372 */ 1373 1374 if (aMovie != NULL) { 1375 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1376 IsQTVRMovie( aMovie ) ? true : false) ); 1377 } else { 1378 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1379 result = TCL_ERROR; 1380 } 1381 break; 1382 } 1383 1384 case kMovieCmdIsscrapmovie: { 1385 1386 /* 1387 * Is there a movie on the clipboard (scrap)? 1388 */ 1389 1390 { 1391 Track targetTrack = NULL; 1392 1393 if (aMovie != NULL) { 1394 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1395 IsScrapMovie( targetTrack ) ? true : false) ); 1396 } else { 1397 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1398 result = TCL_ERROR; 1399 } 1400 } 1401 break; 1402 } 1403 1404 case kMovieCmdIsvisual: { 1405 1406 /* 1407 * Is there there something for our eyes? 1408 */ 1409 1410 if (aMovie != NULL) { 1411 Tcl_SetObjResult( interp, Tcl_NewBooleanObj( 1412 (GetMovieIndTrackType( aMovie, 1, 1413 VisualMediaCharacteristic, 1414 movieTrackCharacteristic ) == NULL) ? false : true) ); 1415 } else { 1416 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1417 result = TCL_ERROR; 1418 } 1419 break; 1420 } 1421 1422 case kMovieCmdNew: { 1423 1424 /* 1425 * Create a new movie. 1426 */ 1427 1428 if (objc != 3) { 1429 Tcl_WrongNumArgs( interp, 2, objv, "fileName" ); 1430 result = TCL_ERROR; 1431 goto error; 1432 } 1433 if (movPtr->fileNamePtr != NULL) { 1434 Tcl_SetObjResult( interp, 1435 Tcl_NewStringObj( "There is already a file name associated with this movie", -1 ) ); 1436 result = TCL_ERROR; 1437 goto error; 1438 } 1439 result = NewMovieCmd(interp, objc, objv, movPtr); 1440 if (result != TCL_OK) { 1441 goto error; 1442 } 1443 /* get rid of the old one */ 1444 break; 1445 } 1446 1447 case kMovieCmdNextInterestingTime: { 1448 TimeValue interestingTime; 1449 TimeValue interestingDuration; 1450 OSType *mediaTypesPtr; 1451 long lType; 1452 int num; 1453 short numMediaTypes = 0; 1454 Tcl_Obj *objPtr; 1455 1456 if (objc == 3) { 1457 movTime = GetMovieTime( aMovie, NULL ); 1458 } else if (objc == 4) { 1459 if (Tcl_GetIntFromObj( interp, objv[3], &intValue ) != TCL_OK) { 1460 Tcl_AddErrorInfo( interp, "\n (processing time value)" ); 1461 result = TCL_ERROR; 1462 goto error; 1463 } 1464 movTime = intValue; 1465 } else { 1466 Tcl_WrongNumArgs( interp, 2, objv, "mediaTypeList ?movieTime?" ); 1467 return TCL_ERROR; 1468 } 1469 1470 /* 1471 * Get media types from list. 1472 */ 1473 1474 if (Tcl_ListObjLength( interp, objv[2], &num ) != TCL_OK) { 1475 return TCL_ERROR; 1476 } 1477 numMediaTypes = (short) num; 1478 mediaTypesPtr = (OSType *) ckalloc( numMediaTypes * sizeof(OSType) ); 1479 for (i = 0; i < numMediaTypes; i++) { 1480 if (Tcl_ListObjIndex( interp, objv[2], i, &objPtr ) != TCL_OK) { 1481 return TCL_ERROR; 1482 } 1483 memcpy( &lType, Tcl_GetString( objPtr ), 4 ); 1484 mediaTypesPtr[i] = EndianU32_NtoB( lType ); 1485 } 1486 1487 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 1488 1489 GetMovieNextInterestingTime( aMovie, 1490 nextTimeMediaSample | nextTimeEdgeOK, 1491 numMediaTypes, mediaTypesPtr, movTime, fixed1, 1492 &interestingTime, &interestingDuration ); 1493 Tcl_ListObjAppendElement( interp, listObjPtr, 1494 Tcl_NewStringObj("-sampletime", -1) ); 1495 Tcl_ListObjAppendElement( interp, listObjPtr, 1496 Tcl_NewLongObj(interestingTime) ); 1497 Tcl_ListObjAppendElement( interp, listObjPtr, 1498 Tcl_NewStringObj("-sampleduration", -1) ); 1499 Tcl_ListObjAppendElement( interp, listObjPtr, 1500 Tcl_NewLongObj(interestingDuration) ); 1501 1502 GetMovieNextInterestingTime( aMovie, 1503 nextTimeMediaEdit | nextTimeEdgeOK, 1504 numMediaTypes, mediaTypesPtr, movTime, fixed1, 1505 &interestingTime, &interestingDuration ); 1506 Tcl_ListObjAppendElement( interp, listObjPtr, 1507 Tcl_NewStringObj("-edittime", -1) ); 1508 Tcl_ListObjAppendElement( interp, listObjPtr, 1509 Tcl_NewLongObj(interestingTime) ); 1510 Tcl_ListObjAppendElement( interp, listObjPtr, 1511 Tcl_NewStringObj("-editduration", -1) ); 1512 Tcl_ListObjAppendElement( interp, listObjPtr, 1513 Tcl_NewLongObj(interestingDuration) ); 1514 1515 GetMovieNextInterestingTime( aMovie, 1516 nextTimeSyncSample | nextTimeEdgeOK, 1517 numMediaTypes, mediaTypesPtr, movTime, fixed1, 1518 &interestingTime, &interestingDuration ); 1519 Tcl_ListObjAppendElement( interp, listObjPtr, 1520 Tcl_NewStringObj("-syncsampletime", -1) ); 1521 Tcl_ListObjAppendElement( interp, listObjPtr, 1522 Tcl_NewLongObj(interestingTime) ); 1523 Tcl_ListObjAppendElement( interp, listObjPtr, 1524 Tcl_NewStringObj("-syncsampleduration", -1) ); 1525 Tcl_ListObjAppendElement( interp, listObjPtr, 1526 Tcl_NewLongObj(interestingDuration) ); 1527 1528 err = GetMoviesError(); 1529 if (err!= noErr) { 1530 Tcl_DecrRefCount( listObjPtr ); 1531 CheckAndSetErrorResult( interp, err ); 1532 return TCL_ERROR; 1533 } 1534 Tcl_SetObjResult( interp, listObjPtr ); 1535 break; 1536 } 1537 1538 case kMovieCmdPan: { 1539 1540 /* 1541 * Set or get pan angle of QTVR pano. 1542 */ 1543 1544 if (objc > 3) { 1545 Tcl_WrongNumArgs( interp, 2, objv, "?angle?" ); 1546 result = TCL_ERROR; 1547 goto error; 1548 } 1549 if (!gHasQTVRManager) { 1550 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1551 "Couldn't find the QTVR manager on this system", -1 ) ); 1552 result = TCL_ERROR; 1553 goto error; 1554 } 1555 if (aMovie != NULL) { 1556 double angle; 1557 1558 if (movPtr->qtvrInstance == NULL) { 1559 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1560 "Couldn't identify this movie as a VR movie", -1 ) ); 1561 result = TCL_ERROR; 1562 goto error; 1563 } 1564 if (objc == 3) { 1565 if (Tcl_GetDoubleFromObj( interp, objv[2], &angle ) != TCL_OK) { 1566 Tcl_AddErrorInfo( interp, 1567 "\n (processing pan command)" ); 1568 } else { 1569 SetPanoramaByDegrees( movPtr->qtvrInstance, kDirLeft, (float) angle ); 1570 } 1571 } else { 1572 Tcl_SetObjResult( interp, Tcl_NewDoubleObj( 1573 QTVRGetPanAngle( movPtr->qtvrInstance ) ) ); 1574 } 1575 } else { 1576 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1577 result = TCL_ERROR; 1578 } 1579 break; 1580 } 1581 1582 case kMovieCmdPanoInfo: { 1583 1584 /* 1585 * Return info about pano movie. 1586 */ 1587 1588 if (objc != 2) { 1589 Tcl_WrongNumArgs( interp, 2, objv, NULL ); 1590 result = TCL_ERROR; 1591 goto error; 1592 } 1593 if (!gHasQTVRManager) { 1594 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1595 "Couldn't find the QTVR manager on this system", -1 ) ); 1596 result = TCL_ERROR; 1597 goto error; 1598 } 1599 if (aMovie != NULL) { 1600 Tcl_Obj *resObjPtr; 1601 UInt32 nodeID = kQTVRCurrentNode; 1602 //UInt32 nodeID = kQTVRDefaultNode; 1603 1604 if (movPtr->qtvrInstance == NULL) { 1605 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1606 "Couldn't identify this movie as a VR movie", -1 ) ); 1607 result = TCL_ERROR; 1608 goto error; 1609 } 1610 1611 if ( TCL_OK != PanoramaGetInfoNode( interp, aMovie, movPtr->qtvrInstance, 1612 nodeID, &resObjPtr )) { 1613 result = TCL_ERROR; 1614 goto error; 1615 } 1616 Tcl_SetObjResult( interp, resObjPtr ); 1617 } else { 1618 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1619 result = TCL_ERROR; 1620 } 1621 break; 1622 } 1623 1624 case kMovieCmdPaste: { 1625 1626 /* 1627 * Paste the movie or whatever that can be imported. Works differently 1628 * depending on if '-mcedit 1' (MCIsEditingEnabled) or not. 1629 */ 1630 1631 if (objc > 3) { 1632 Tcl_WrongNumArgs( interp, 2, objv, "?option?" ); 1633 result = TCL_ERROR; 1634 goto error; 1635 } 1636 if (aMovie != NULL) { 1637 sizeMayChange = false; 1638 if ((movPtr->aController != NULL) && 1639 MCIsEditingEnabled( movPtr->aController )) { 1640 long modifiers = 0L; 1641 char *charPtr; 1642 1643 if (objc == 3) { 1644 1645 /* 1646 * Set modifier flags for the controller. 1647 */ 1648 1649 charPtr = Tcl_GetString( objv[2] ); 1650 if (strcmp(charPtr, "scaled") == 0) { 1651 modifiers |= shiftKey; 1652 modifiers |= optionKey; 1653 sizeMayChange = true; 1654 } else if (strcmp(charPtr, "replace") == 0) { 1655 modifiers |= shiftKey; 1656 } else if (strcmp(charPtr, "parallel") == 0) { 1657 modifiers |= optionKey; 1658 sizeMayChange = true; 1659 1660#if TARGET_OS_MAC 1661 } else if (strcmp(charPtr, "dialog") == 0) { 1662 modifiers |= controlKey; 1663 modifiers |= optionKey; 1664 sizeMayChange = true; 1665#endif 1666 1667 } else { 1668 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1669 "unrecognized paste option", -1 ) ); 1670 result = TCL_ERROR; 1671 goto error; 1672 } 1673 } 1674 result = LogUndoState( movPtr, interp ); 1675 compErr = MCSetUpEditMenu( movPtr->aController, modifiers, NULL ); 1676 if (compErr != noErr) { 1677 CheckAndSetErrorResult( interp, noErr ); 1678 result = TCL_ERROR; 1679 goto error; 1680 } 1681 compErr = MCPaste( movPtr->aController, NULL ); 1682 if (compErr != noErr) { 1683 CheckAndSetErrorResult( interp, noErr ); 1684 result = TCL_ERROR; 1685 goto error; 1686 } 1687 } else { 1688 if (objc == 3) { 1689 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1690 "Need a controller with enabled editing to accept paste options", -1 ) ); 1691 result = TCL_ERROR; 1692 goto error; 1693 } 1694 tmpMovie = NewMovieFromScrap(0); 1695 if (tmpMovie != NULL) { 1696 result = LogUndoState( movPtr, interp ); 1697 PasteMovieSelection( aMovie, tmpMovie ); 1698 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 1699 result = TCL_ERROR; 1700 goto error; 1701 } else { 1702 DisposeMovie(tmpMovie); 1703 } 1704 } else { 1705 CheckAndSetErrorResult( interp, noErr ); 1706 result = TCL_ERROR; 1707 goto error; 1708 } 1709 } 1710 1711 /* 1712 * Option here: we choose to only change the size if there 1713 * was nothing visual before (mwidth/mheight = 0). 1714 * Else it gets scaled. 1715 */ 1716 1717 if ((movPtr->mwidth == 0) || (movPtr->mheight == 0)) { 1718 Rect aRect; 1719 1720 GetMovieBox( aMovie, &aRect ); 1721 movPtr->mwidth = aRect.right - aRect.left; 1722 movPtr->mheight = aRect.bottom - aRect.top; 1723 sizeMayChange = true; 1724 } 1725 if (movPtr->aController != NULL) { 1726 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 1727 MCMovieChanged( movPtr->aController, aMovie ); 1728 if (sizeMayChange) { 1729 MoviePlayerWorldChanged( clientData ); 1730 } 1731 } else { 1732 MoviePlayerWorldChanged( clientData ); 1733 } 1734 } else { 1735 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1736 result = TCL_ERROR; 1737 } 1738 break; 1739 } 1740 1741 case kMovieCmdPicture: { 1742 1743 /* 1744 * Make a tk image from a time in a movie. 1745 */ 1746 1747 if (aMovie ) { 1748 int dstWidth = 0; 1749 int dstHeight = 0; 1750 char *charPtr; 1751 1752 if (objc < 4) { 1753 Tcl_WrongNumArgs( interp, 2, objv, 1754 "time imageName ?-width width -height height?" ); 1755 result = TCL_ERROR; 1756 goto error; 1757 } 1758 1759 /* 1760 * If not visual then error. 1761 */ 1762 1763 if (GetMovieIndTrackType( aMovie, 1, VisualMediaCharacteristic, 1764 movieTrackCharacteristic ) == NULL) { 1765 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1766 "No visual media characteristics in movie", -1 ) ); 1767 result = TCL_ERROR; 1768 goto error; 1769 } 1770 if (Tcl_GetIntFromObj( interp, objv[2], &intValue ) != TCL_OK) { 1771 Tcl_AddErrorInfo( interp, "\n (processing time value)" ); 1772 result = TCL_ERROR; 1773 goto error; 1774 } 1775 movTime = intValue; 1776 thePic = GetMoviePict( aMovie, movTime ); 1777 if (thePic == NULL) { 1778 CheckAndSetErrorResult( interp, noErr ); 1779 result = TCL_ERROR; 1780 goto error; 1781 } 1782 1783 /* Process any -width and -height options. */ 1784 for (iarg = 4; iarg < objc; iarg = iarg + 2) { 1785 charPtr = Tcl_GetString( objv[iarg] ); 1786 if (strcmp(charPtr, "-width") == 0) { 1787 if (Tcl_GetIntFromObj( interp, objv[iarg+1], &dstWidth ) 1788 != TCL_OK) { 1789 Tcl_AddErrorInfo( interp, "\n (processing -width value)" ); 1790 result = TCL_ERROR; 1791 goto error; 1792 } 1793 } else if (strcmp(charPtr, "-height") == 0) { 1794 if (Tcl_GetIntFromObj( interp, objv[iarg+1], &dstHeight ) 1795 != TCL_OK) { 1796 Tcl_AddErrorInfo( interp, "\n (processing -height value)" ); 1797 result = TCL_ERROR; 1798 goto error; 1799 } 1800 } else { 1801 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1802 "unrecognized option", -1 ) ); 1803 result = TCL_ERROR; 1804 goto error; 1805 } 1806 } 1807 result = ConvertPictureToTkPhoto( interp, thePic, 1808 dstWidth, dstHeight, Tcl_GetString(objv[3]) ); 1809 KillPicture( thePic ); 1810 } else { 1811 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1812 result = TCL_ERROR; 1813 } 1814 break; 1815 } 1816 1817 case kMovieCmdPlay: { 1818 1819 /* 1820 * Play the movie from its present position. 1821 */ 1822 1823 if (aMovie ) { 1824 if (!Tk_IsMapped(movPtr->tkwin) && 1825 (GetMovieIndTrackType( aMovie, 1, VisualMediaCharacteristic, 1826 movieTrackCharacteristic ) != NULL)) { 1827 Tcl_SetObjResult( interp, 1828 Tcl_NewStringObj( "Movie not displayed", -1 ) ); 1829 result = TCL_ERROR; 1830 } else { 1831 if (movPtr->aController != NULL) { 1832 rate = X2Fix(movPtr->preferredRate); 1833 MCDoAction( movPtr->aController, mcActionPlay, (void *) rate ); 1834 } else { 1835 1836 /* 1837 * If at end, set movie time to beginning before playing. 1838 */ 1839 1840 if (IsMovieDone( aMovie )) { 1841 if (GetMoviePreferredRate(aMovie) > 0) { 1842 SetMovieTimeValue( aMovie, 0 ); 1843 } else { 1844 SetMovieTimeValue( aMovie, GetMovieDuration(aMovie) ); 1845 } 1846 } 1847 StartMovie( aMovie ); 1848 } 1849 } 1850 } else { 1851 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1852 result = TCL_ERROR; 1853 } 1854 break; 1855 } 1856 1857 case kMovieCmdPlayHints: { 1858 if (aMovie != NULL) { 1859 int hintFlag = 0L; 1860 1861 flags = 0L; 1862 mask = 0L; 1863 1864 for (iarg = 2; iarg < objc; iarg += 2) { 1865 if (Tcl_GetIndexFromObj( interp, objv[iarg], allMoviePlayHintsOpts, 1866 "playhints option", TCL_EXACT, &optIndex ) != TCL_OK ) { 1867 result = TCL_ERROR; 1868 goto error; 1869 } 1870 if (iarg + 1 == objc) { 1871 resultObjPtr = Tcl_GetObjResult( interp ); 1872 Tcl_AppendStringsToObj( resultObjPtr, "value for \"", 1873 Tcl_GetString(objv[iarg]), "\"missing", 1874 (char *) NULL ); 1875 result = TCL_ERROR; 1876 goto error; 1877 } 1878 1879 /* 1880 * All values are boolean. 1881 */ 1882 if (Tcl_GetBooleanFromObj( interp, objv[iarg+1], 1883 &boolValue ) != TCL_OK) { 1884 Tcl_AddErrorInfo( interp, 1885 "\n (processing -playhints option)" ); 1886 result = TCL_ERROR; 1887 goto error; 1888 break; 1889 } 1890 1891 switch (optIndex) { 1892 case kMoviePlayHintsOptScrubMode: { 1893 hintFlag = hintsScrubMode; 1894 } 1895 case kMoviePlayHintsOptUseSoundInterp: { 1896 hintFlag = hintsUseSoundInterp; 1897 } 1898 case kMoviePlayHintsOptAllowInterlace: { 1899 hintFlag = hintsAllowInterlace; 1900 } 1901 case kMoviePlayHintsOptAllowBlacklining: { 1902 hintFlag = hintsAllowBlacklining; 1903 } 1904 case kMoviePlayHintsOptDontPurge: { 1905 hintFlag = hintsDontPurge; 1906 } 1907 case kMoviePlayHintsOptInactive: { 1908 hintFlag = hintsInactive; 1909 } 1910 case kMoviePlayHintsOptHighQuality: { 1911 hintFlag = hintsHighQuality; 1912 } 1913 } 1914 if (boolValue) { 1915 flags |= hintFlag; 1916 } else { 1917 flags &= ~hintFlag; 1918 } 1919 mask |= hintFlag; 1920 } 1921 SetMoviePlayHints( aMovie, flags, mask ); 1922 } else { 1923 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1924 result = TCL_ERROR; 1925 } 1926 break; 1927 } 1928 1929 case kMovieCmdRate: { 1930 1931 /* 1932 * Set or get the movie play rate. 1933 */ 1934 1935 if (aMovie != NULL) { 1936 if (objc == 2) { 1937 Tcl_SetObjResult( interp, Tcl_NewDoubleObj( 1938 Fix2X( GetMovieRate(aMovie) ) ) ); 1939 } else if (objc == 3) { 1940 if (Tcl_GetDoubleFromObj( interp, objv[2], &theRate ) != TCL_OK) { 1941 Tcl_AddErrorInfo( interp, 1942 "\n (processing rate command)" ); 1943 } else { 1944 rate = X2Fix(theRate); 1945 SetMovieRate( aMovie, rate ); 1946 } 1947 } else { 1948 Tcl_WrongNumArgs( interp, 2, objv, "?rate?" ); 1949 result = TCL_ERROR; 1950 goto error; 1951 } 1952 if (movPtr->aController != NULL) { 1953 MCMovieChanged( movPtr->aController, aMovie ); 1954 } 1955 } else { 1956 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 1957 result = TCL_ERROR; 1958 } 1959 break; 1960 } 1961 1962 case kMovieCmdSave: { 1963 1964 /* 1965 * Save the movie. If there was a movie resource in the orig movie, save in 1966 * resource fork, else save in the data fork. 1967 */ 1968 1969 if (aMovie != NULL) { 1970 if (objc != 2) { 1971 Tcl_WrongNumArgs( interp, 2, objv, NULL ); 1972 result = TCL_ERROR; 1973 goto error; 1974 } 1975 if (movPtr->fileNamePtr == NULL) { 1976 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1977 "Have no file name. Use \"saveas\" or \"flatten\" instead", -1 ) ); 1978 result = TCL_ERROR; 1979 goto error; 1980 } 1981 1982 /* 1983 * Translate file name to FSSpec. 1984 */ 1985 1986 err = QTTclNativePathNameToFSSpec( movPtr->interp, 1987 Tcl_GetString( movPtr->fileNamePtr ), &fss ); 1988 1989 if (err == fnfErr) { 1990 Tcl_AppendStringsToObj( Tcl_GetObjResult( interp ), 1991 "File not found: ", 1992 Tcl_GetString( movPtr->fileNamePtr ), 1993 (char *) NULL ); 1994 result = TCL_ERROR; 1995 goto error; 1996 } 1997 if (err != noErr) { 1998 Tcl_SetObjResult( interp, Tcl_NewStringObj( 1999 "Unable to make a FSSpec from file name", -1 ) ); 2000 result = TCL_ERROR; 2001 goto error; 2002 } 2003#if 0 2004extern OSErr 2005OpenMovieStorage( 2006 Handle dataRef, 2007 OSType dataRefType, 2008 long flags, 2009 DataHandler * outDataHandler) 2010#endif 2011 if (noErr != OpenMovieFile( &fss, &movieResFile, fsRdWrPerm )) { 2012 CheckAndSetErrorResult( interp, noErr ); 2013 result = TCL_ERROR; 2014 goto error; 2015 } 2016 if (movPtr->resourceNumber == -1) { 2017 2018 /* We have probably the movie in the data fork. */ 2019 resId = movieInDataForkResID; 2020 } else { 2021 2022 /* Save in the resource fork. */ 2023 resId = movPtr->resourceNumber; 2024 } 2025 2026 if (noErr != UpdateMovieResource( aMovie, movieResFile, resId, NULL )) { 2027 CheckAndSetErrorResult( interp, noErr ); 2028 result = TCL_ERROR; 2029 } 2030#if 0 2031extern OSErr 2032CloseMovieStorage(DataHandler dh) 2033#endif 2034 CloseMovieFile(movieResFile); 2035 2036 } else { 2037 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2038 result = TCL_ERROR; 2039 } 2040 break; 2041 } 2042 2043 case kMovieCmdSaveas: { 2044 2045 /* 2046 * Save the movie in a new file. 2047 */ 2048 2049 if (aMovie != NULL) { 2050 Handle dataRef = NULL; 2051 OSType dataRefType; 2052 DataHandler dataHandler = 0; 2053 2054 if (objc != 3) { 2055 Tcl_WrongNumArgs( interp, 2, objv, "fileName" ); 2056 result = TCL_ERROR; 2057 goto error; 2058 } 2059 2060 result = QTTclNewDataRefFromUTF8Obj(interp, objv[2], &dataRef, &dataRefType); 2061 if (result != TCL_OK) { 2062 goto error; 2063 } 2064 flags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile | 2065 createMovieFileDontCreateMovie; 2066 err = CreateMovieStorage(dataRef, dataRefType, ksigMoviePlayer, 2067 smCurrentScript, flags, &dataHandler, NULL); 2068 if (noErr != err) { 2069 CheckAndSetErrorResult( interp, noErr ); 2070 result = TCL_ERROR; 2071 goto error; 2072 } 2073 resId = movieInDataForkResID; 2074 if (noErr != AddMovieToStorage(aMovie, dataHandler)) { 2075 if (dataHandler) { 2076 err = CloseMovieStorage(dataHandler); 2077 } 2078 if (dataRef) { 2079 DisposeHandle(dataRef); 2080 } 2081 CheckAndSetErrorResult( interp, noErr ); 2082 result = TCL_ERROR; 2083 goto error; 2084 } 2085 movPtr->resourceNumber = resId; 2086 2087 if (movPtr->fileNamePtr != NULL) { 2088 Tcl_DecrRefCount( movPtr->fileNamePtr ); 2089 } 2090 movPtr->fileNamePtr = objv[2]; 2091 Tcl_IncrRefCount( movPtr->fileNamePtr ); 2092 movPtr->filename = Tcl_GetString( objv[2] ); 2093 if (dataHandler) { 2094 err = CloseMovieStorage(dataHandler); 2095 } 2096 ClearMovieChanged( aMovie ); 2097 if (dataRef) { 2098 DisposeHandle(dataRef); 2099 } 2100 } else { 2101 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2102 result = TCL_ERROR; 2103 } 2104 break; 2105 } 2106 2107 case kMovieCmdSelect: { 2108 2109 /* 2110 * Select a section of movie. A movie selection shall invalidate any track selection. 2111 */ 2112 2113 if (aMovie != NULL) { 2114 if (objc == 2) { 2115 2116 /* 2117 * Get the movie selection. 2118 */ 2119 2120 if (aMovie != NULL) { 2121 GetMovieSelection( aMovie, &movTime, &movDuration ); 2122 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2123 result = TCL_ERROR; 2124 goto error; 2125 } 2126 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 2127 Tcl_ListObjAppendElement( interp, listObjPtr, 2128 Tcl_NewLongObj(movTime) ); 2129 Tcl_ListObjAppendElement( interp, listObjPtr, 2130 Tcl_NewLongObj(movDuration) ); 2131 Tcl_SetObjResult( interp, listObjPtr ); 2132 } else { 2133 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2134 result = TCL_ERROR; 2135 } 2136 2137 } else if (objc == 3) { 2138 char *strObjv2 = Tcl_GetString(objv[2]); 2139 2140 if (strcmp(strObjv2, "clear") == 0) { 2141 result = LogUndoState( movPtr, interp ); 2142 ClearMovieSelection( aMovie ); 2143 if (movPtr->aController != NULL) { 2144 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 2145 MCMovieChanged( movPtr->aController, aMovie ); 2146 } else { 2147 MoviePlayerWorldChanged( clientData ); 2148 } 2149 } else if (strcmp(strObjv2, "all") == 0) { 2150 SetMovieSelection( aMovie, 0, GetMovieDuration( aMovie ) ); 2151 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2152 result = TCL_ERROR; 2153 goto error; 2154 } 2155 movPtr->trackSelect->trackID = 0; 2156 } else if (strcmp(strObjv2, "end") == 0) { 2157 SetMovieSelection( aMovie, GetMovieTime( aMovie, NULL ), 0 ); 2158 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2159 result = TCL_ERROR; 2160 goto error; 2161 } 2162 movPtr->trackSelect->trackID = 0; 2163 } else if (strcmp(strObjv2, "none") == 0) { 2164 SetMovieSelection( aMovie, GetMovieTime( aMovie, NULL ), 0 ); 2165 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2166 result = TCL_ERROR; 2167 goto error; 2168 } 2169 movPtr->trackSelect->trackID = 0; 2170 } else { 2171 if (GetMovieStartTimeFromObj( interp, aMovie, objv[2], &longValue ) != TCL_OK) { 2172 goto error; 2173 } 2174 movTime = longValue; 2175 movDuration = 0; 2176 SetMovieSelection( aMovie, movTime, movDuration ); 2177 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2178 result = TCL_ERROR; 2179 goto error; 2180 } 2181 movPtr->trackSelect->trackID = 0; 2182 } 2183 } else if (objc == 4) { 2184 if (GetMovieStartTimeFromObj( interp, aMovie, objv[2], &longValue ) != TCL_OK) { 2185 goto error; 2186 } 2187 movTime = longValue; 2188 if (GetMovieDurationFromObj( interp, aMovie, objv[3], movTime, &longValue ) != TCL_OK) { 2189 goto error; 2190 } 2191 movDuration = longValue; 2192 SetMovieSelection( aMovie, movTime, movDuration ); 2193 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2194 result = TCL_ERROR; 2195 goto error; 2196 } 2197 movPtr->trackSelect->trackID = 0; 2198 } else { 2199 Tcl_WrongNumArgs( interp, 2, objv, "?startTime? ?duration?" ); 2200 result = TCL_ERROR; 2201 goto error; 2202 } 2203 if (movPtr->aController != NULL) { 2204 MCMovieChanged( movPtr->aController, aMovie ); 2205 } 2206 } else { 2207 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2208 result = TCL_ERROR; 2209 } 2210 break; 2211 } 2212 2213 case kMovieCmdSetpreferredrate: { 2214 2215 /* 2216 * Set the movie's preferred play rate. Now obsolete! 2217 */ 2218 2219 if (aMovie != NULL) { 2220 if (objc == 3) { 2221 if (Tcl_GetDoubleFromObj( interp, objv[2], &theRate ) != TCL_OK) { 2222 Tcl_AddErrorInfo( interp, 2223 "\n (processing rate command)" ); 2224 } else { 2225 rate = X2Fix(theRate); 2226 movPtr->preferredRate = theRate; 2227 if (movPtr->aController != NULL) { 2228 2229 /* For a controller, the movie's play rate is set from the play action. */ 2230 2231 SetMoviePreferredRate( aMovie, rate ); 2232 } else { 2233 SetMoviePreferredRate( aMovie, rate ); 2234 } 2235 } 2236 } else { 2237 Tcl_WrongNumArgs( interp, 2, objv, "rate"); 2238 result = TCL_ERROR; 2239 goto error; 2240 } 2241 if (movPtr->aController != NULL) { 2242 MCMovieChanged( movPtr->aController, aMovie ); 2243 } 2244 } else { 2245 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2246 result = TCL_ERROR; 2247 } 2248 break; 2249 } 2250 2251 case kMovieCmdSetrate: { 2252 2253 /* 2254 * Set the movie play rate. Now obsolete! 2255 */ 2256 2257 if (aMovie != NULL) { 2258 if (objc == 3) { 2259 if (Tcl_GetDoubleFromObj( interp, objv[2], &theRate ) != TCL_OK) { 2260 Tcl_AddErrorInfo( interp, 2261 "\n (processing rate command)" ); 2262 } else { 2263 rate = X2Fix(theRate); 2264 SetMovieRate( aMovie, rate ); 2265 } 2266 } else { 2267 Tcl_WrongNumArgs( interp, 2, objv, "rate"); 2268 result = TCL_ERROR; 2269 goto error; 2270 } 2271 if (movPtr->aController != NULL) { 2272 MCMovieChanged( movPtr->aController, aMovie ); 2273 } 2274 } else { 2275 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2276 result = TCL_ERROR; 2277 } 2278 break; 2279 } 2280 2281 case kMovieCmdSettime: { 2282 2283 /* 2284 * Set the movie time. Now obsolete, use "time". 2285 */ 2286 2287 if (objc != 3) { 2288 Tcl_WrongNumArgs( interp, 2, objv, "time" ); 2289 result = TCL_ERROR; 2290 } else { 2291 if (aMovie != NULL) { 2292 if (Tcl_GetIntFromObj( interp, objv[2], &intValue ) != TCL_OK) { 2293 Tcl_AddErrorInfo( interp, "\n (processing time value)" ); 2294 result = TCL_ERROR; 2295 goto error; 2296 } 2297 movTime = intValue; 2298 SetMovieTimeValue( aMovie, movTime ); 2299 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2300 result = TCL_ERROR; 2301 goto error; 2302 } 2303 if (movPtr->aController != NULL) { 2304 MCMovieChanged(movPtr->aController, aMovie); 2305 } 2306 } else { 2307 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2308 result = TCL_ERROR; 2309 } 2310 } 2311 break; 2312 } 2313 2314 case kMovieCmdSize: { 2315 2316 /* 2317 * Return the movies "natural" size excluding any movie controller. 2318 */ 2319 2320 if (aMovie != NULL) { 2321 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 2322 Tcl_ListObjAppendElement( interp, listObjPtr, 2323 Tcl_NewLongObj(movPtr->mwidth) ); 2324 Tcl_ListObjAppendElement( interp, listObjPtr, 2325 Tcl_NewLongObj(movPtr->mheight) ); 2326 Tcl_SetObjResult( interp, listObjPtr ); 2327 } else { 2328 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2329 result = TCL_ERROR; 2330 } 2331 break; 2332 } 2333 2334 case kMovieCmdUndocumeted1: { 2335 2336 /* 2337 * Sprite Subcommand (not implemented). 2338 */ 2339 2340 if (aMovie != NULL) { 2341 ProcessSpriteSubcmd(clientData, interp, objc-2, objv+2); 2342 } else { 2343 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2344 result = TCL_ERROR; 2345 } 2346 break; 2347 } 2348 2349 case kMovieCmdStep: { 2350 2351 /* 2352 * Step through the movie. 2353 */ 2354 2355 long numSteps = 1; 2356 if (objc > 2) { 2357 if (Tcl_GetIntFromObj( interp, objv[2], &intValue ) != TCL_OK) { 2358 Tcl_AddErrorInfo( interp, "\n (processing numSteps value)" ); 2359 result = TCL_ERROR; 2360 goto error; 2361 } 2362 numSteps = intValue; 2363 } 2364 if (aMovie != NULL) { 2365 if (movPtr->aController != NULL) { 2366 MCDoAction( movPtr->aController, mcActionStep, 2367 (void*) numSteps ); 2368 MCMovieChanged( movPtr->aController, aMovie ); 2369 } else { 2370 long i; 2371 TimeValue intTime; 2372 TimeValue intDur; 2373 TimeValue curTime; 2374 long num = numSteps; 2375 2376 if (num < 0) { 2377 num = 0 - num; 2378 } 2379 for (i = 0; i < num; i++) { 2380 curTime = GetMovieTime( aMovie, NULL ); 2381 GetMovieNextInterestingTime( aMovie, nextTimeStep, 2382 0, 0, curTime, numSteps, &intTime, &intDur ); 2383 SetMovieTimeValue( aMovie, intTime ); 2384 } 2385 } 2386 } else { 2387 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2388 result = TCL_ERROR; 2389 } 2390 break; 2391 } 2392 2393 case kMovieCmdStop: { 2394 2395 /* 2396 * Stop the movie from playing. 2397 */ 2398 2399 if (aMovie != NULL) { 2400 if (movPtr->aController != NULL) { 2401 MCDoAction( movPtr->aController, mcActionPlay, 0 ); 2402 MCDoAction( movPtr->aController, mcActionSetLooping, (void *) false ); 2403 } else { 2404 StopMovie(aMovie); 2405 } 2406 } else { 2407 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2408 result = TCL_ERROR; 2409 } 2410 break; 2411 } 2412 2413 case kMovieCmdTilt: { 2414 2415 /* 2416 * Set or get tilt angle of QTVR pano. 2417 */ 2418 2419 if (objc > 3) { 2420 Tcl_WrongNumArgs( interp, 2, objv, "?angle?" ); 2421 result = TCL_ERROR; 2422 goto error; 2423 } 2424 if (!gHasQTVRManager) { 2425 Tcl_SetObjResult( interp, Tcl_NewStringObj( 2426 "Couldn't find the QTVR manager on this system", -1 ) ); 2427 result = TCL_ERROR; 2428 goto error; 2429 } 2430 if (aMovie != NULL) { 2431 double angle; 2432 2433 if (movPtr->qtvrInstance == NULL) { 2434 Tcl_SetObjResult( interp, Tcl_NewStringObj( 2435 "Couldn't identify this movie as a VR movie", -1 ) ); 2436 result = TCL_ERROR; 2437 goto error; 2438 } 2439 if (objc == 3) { 2440 if (Tcl_GetDoubleFromObj( interp, objv[2], &angle ) != TCL_OK) { 2441 Tcl_AddErrorInfo( interp, 2442 "\n (processing tilt command)" ); 2443 } else { 2444 SetPanoramaByDegrees( movPtr->qtvrInstance, kDirUp, (float) angle ); 2445 } 2446 } else { 2447 angle = QTVRGetTiltAngle( movPtr->qtvrInstance ); 2448 Tcl_SetObjResult( interp, Tcl_NewDoubleObj( angle ) ); 2449 } 2450 } else { 2451 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2452 result = TCL_ERROR; 2453 } 2454 break; 2455 } 2456 2457 case kMovieCmdTime: { 2458 2459 /* 2460 * Set or get the movie time. 2461 */ 2462 2463 if (objc == 2) { 2464 if (aMovie != NULL) { 2465 Tcl_SetObjResult( interp, Tcl_NewLongObj( 2466 GetMovieTime( aMovie, NULL ) ) ); 2467 } else { 2468 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2469 result = TCL_ERROR; 2470 } 2471 } else if (objc == 3) { 2472 if (aMovie != NULL) { 2473 if (Tcl_GetIntFromObj( interp, objv[2], &intValue ) != TCL_OK) { 2474 Tcl_AddErrorInfo( interp, "\n (processing time value)" ); 2475 result = TCL_ERROR; 2476 goto error; 2477 } 2478 movTime = intValue; 2479 SetMovieTimeValue( aMovie, movTime ); 2480 if (noErr != CheckAndSetErrorResult( interp, noErr )) { 2481 result = TCL_ERROR; 2482 goto error; 2483 } 2484 if (movPtr->aController != NULL) { 2485 MCMovieChanged( movPtr->aController, aMovie ); 2486 } 2487 } else { 2488 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2489 result = TCL_ERROR; 2490 } 2491 } else { 2492 Tcl_WrongNumArgs( interp, 2, objv, "?time?" ); 2493 result = TCL_ERROR; 2494 } 2495 break; 2496 } 2497 2498 case kMovieCmdTimeCode: { 2499 2500 /* 2501 * The tracks sub command. 2502 */ 2503 2504 if (aMovie != NULL) { 2505 if (TCL_OK != TimeCodeCmd( interp, movPtr, objc - 2, objv + 2 )) { 2506 result = TCL_ERROR; 2507 } 2508 } else { 2509 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2510 result = TCL_ERROR; 2511 } 2512 break; 2513 } 2514 2515 case kMovieCmdTracks: { 2516 2517 /* 2518 * The tracks sub command. 2519 */ 2520 2521 if (aMovie != NULL) { 2522 if (TCL_OK != ProcessTracksObjCmd( clientData, interp, objc - 2, objv + 2 )) { 2523 result = TCL_ERROR; 2524 } 2525 } else { 2526 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2527 result = TCL_ERROR; 2528 } 2529 break; 2530 } 2531 2532 case kMovieCmdUndo: { 2533 2534 /* 2535 * Either checkpoint or undo a change. 2536 */ 2537 2538 if (aMovie != NULL) { 2539 if (objc == 3) { 2540 if (strcmp(Tcl_GetString(objv[2]), "set") == 0) { 2541 result = LogUndoState( movPtr, interp ); 2542 } else { 2543 if (Tcl_GetIntFromObj( interp, objv[2], &intValue ) 2544 != TCL_OK) { 2545 Tcl_AddErrorInfo( interp, 2546 "\n (processing undoLevel value)" ); 2547 result = TCL_ERROR; 2548 goto error; 2549 } 2550 undoLevel = intValue; 2551 if (undoLevel < 0 || undoLevel >= movPtr->undoCount) { 2552 Tcl_SetObjResult( interp, Tcl_NewStringObj( 2553 "Invalid Undo Level", -1 ) ); 2554 result = TCL_ERROR; 2555 goto error; 2556 } 2557 err = UseMovieEditState( aMovie, movPtr->editStates[undoLevel] ); 2558 if (err != noErr) { 2559 CheckAndSetErrorResult( interp, err ); 2560 result = TCL_ERROR; 2561 goto error; 2562 } 2563 for (i = undoLevel; i < movPtr->undoCount; i++) { 2564 DisposeMovieEditState( movPtr->editStates[i] ); 2565 } 2566 movPtr->undoCount = undoLevel; 2567 if (movPtr->aController != NULL) { 2568 MCDoAction( movPtr->aController, mcActionMovieEdited, NULL ); 2569 MCMovieChanged( movPtr->aController, aMovie ); 2570 } 2571 } 2572 } else if (objc == 2) { 2573 Tcl_SetObjResult( interp, Tcl_NewIntObj( movPtr->undoCount ) ); 2574 } else { 2575 Tcl_WrongNumArgs( interp, 2, objv, "set | level" ); 2576 result = TCL_ERROR; 2577 } 2578 } else { 2579 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2580 result = TCL_ERROR; 2581 } 2582 break; 2583 } 2584 2585 case kMovieCmdUserData: { 2586 2587 /* 2588 * The userdata command. 2589 */ 2590 2591 if (aMovie != NULL) { 2592 UserData userData = 0; 2593 2594 userData = GetMovieUserData( aMovie ); 2595 if (userData == NULL) { 2596 CheckAndSetErrorResult( interp, noErr ); 2597 result = TCL_ERROR; 2598 goto error; 2599 } 2600 if (objc == 2) { 2601 if (TCL_OK != GetUserDataListCmd( userData, interp )) { 2602 result = TCL_ERROR; 2603 } 2604 } else if ((objc > 2) && (objc % 2 == 0)) { 2605 if (TCL_OK != SetUserDataListCmd( userData, interp, objc - 2, objv + 2 )) { 2606 result = TCL_ERROR; 2607 } 2608 } else { 2609 Tcl_WrongNumArgs( interp, 2, objv, "?options?" ); 2610 result = TCL_ERROR; 2611 } 2612 } else { 2613 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2614 result = TCL_ERROR; 2615 } 2616 break; 2617 } 2618 2619 case kMovieCmdUndocumeted2: { 2620 2621 /* 2622 * Vector Subcommand. 2623 */ 2624 2625 if (aMovie != NULL) { 2626 ProcessVectorSubcmd(clientData, interp, objc-2, objv+2); 2627 } else { 2628 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 2629 result = TCL_ERROR; 2630 } 2631 } 2632 } 2633 2634error: 2635 Tcl_Release((ClientData) movPtr); 2636 return result; 2637} 2638 2639/* 2640 *---------------------------------------------------------------------- 2641 * 2642 * ComressMovieCmd -- 2643 * 2644 * Compress the movie. 2645 * 2646 * Results: 2647 * The return value is a standard Tcl result. If TCL_ERROR is 2648 * returned, then the interp's result contains an error message. 2649 * 2650 * Side effects: 2651 * None. 2652 * 2653 *---------------------------------------------------------------------- 2654 */ 2655 2656static int 2657ComressMovieCmd(Tcl_Interp *interp, 2658 int objc, Tcl_Obj *CONST objv[], 2659 MoviePlayer *movPtr) 2660{ 2661 Handle dataRef = NULL; 2662 OSType dataRefType; 2663 ComponentInstance videoCodec; 2664 Boolean canceled; 2665 OSErr err = noErr; 2666 int result = TCL_OK; 2667 2668 /* 2669 * Translate file name to Data Reference. 2670 */ 2671 result = QTTclNewDataRefFromUTF8Obj(interp, objv[2], 2672 &dataRef, &dataRefType); 2673 if (result != TCL_OK) { 2674 goto error; 2675 } 2676 videoCodec = NULL; 2677 if (objc == 4) { 2678 2679 /* Have a codec to work with. We do not need 'EndianU32_NtoB'! */ 2680 2681 videoCodec = OpenDefaultComponent( MovieExportType, 2682 MovieFileType ); 2683 if (videoCodec == NULL) { 2684 Tcl_SetObjResult( interp, 2685 Tcl_NewStringObj( "Codec not found", -1 ) ); 2686 result = TCL_ERROR; 2687 goto error; 2688 } 2689 MovieExportDoUserDialog( videoCodec, movPtr->aMovie, NULL, 2690 0, GetMovieDuration(movPtr->aMovie), &canceled ); 2691 if (canceled) { 2692 2693 /* This is actually not an error, just to clean up things. */ 2694 goto error; 2695 } 2696 } 2697 err = ConvertMovieToDataRef(movPtr->aMovie, 0, dataRef, dataRefType, 2698 MovieFileType, ksigMoviePlayer, 0, videoCodec); 2699 if (noErr != err) { 2700 CheckAndSetErrorResult( interp, err ); 2701 result = TCL_ERROR; 2702 goto error; 2703 } 2704 2705error: 2706 if (dataRef) { 2707 DisposeHandle(dataRef); 2708 } 2709 if (videoCodec != NULL) { 2710 CloseComponent( videoCodec ); 2711 } 2712 return result; 2713} 2714 2715/* 2716 *---------------------------------------------------------------------- 2717 * 2718 * FlattenMovieCmd -- 2719 * 2720 * Flatten the movie into the datafork of a new file. 2721 * A separate mechanism is used for QTVR panos. 2722 * 2723 * Results: 2724 * The return value is a standard Tcl result. If TCL_ERROR is 2725 * returned, then the interp's result contains an error message. 2726 * 2727 * Side effects: 2728 * New movie may be assiciated with movie widget. 2729 * 2730 *---------------------------------------------------------------------- 2731 */ 2732 2733static int 2734FlattenMovieCmd(Tcl_Interp *interp, 2735 int objc, Tcl_Obj *CONST objv[], 2736 MoviePlayer *movPtr) 2737{ 2738 int iarg; 2739 int optIndex; 2740 int boolValue; 2741 int showDialog; 2742 long flags; 2743 Tcl_Obj *obj; 2744 Handle dataRef = NULL; 2745 OSType dataRefType; 2746 ComponentDescription desc; 2747 MovieExportComponent exporter = NULL; 2748 OSErr err = noErr; 2749 int result = TCL_OK; 2750 2751 /* 2752 * Set default sub options for flatten. 2753 */ 2754 2755 flags = flattenAddMovieToDataFork | flattenForceMovieResourceBeforeMovieData; 2756 showDialog = false; 2757 2758 for (iarg = 3; iarg < objc; iarg += 2) { 2759 if (Tcl_GetIndexFromObj( interp, objv[iarg], allMovieFlattenOpts, 2760 "flatten option", TCL_EXACT, &optIndex ) != TCL_OK ) { 2761 result = TCL_ERROR; 2762 goto error; 2763 } 2764 if (iarg + 1 == objc) { 2765 Tcl_AppendStringsToObj( Tcl_GetObjResult(interp), 2766 "value for \"", Tcl_GetString(objv[iarg]), "\"missing", 2767 (char *) NULL ); 2768 result = TCL_ERROR; 2769 goto error; 2770 } 2771 2772 switch (optIndex) { 2773 2774 case kMovieFlattenOptDialog: { 2775 if (Tcl_GetBooleanFromObj( interp, objv[iarg+1], 2776 &showDialog ) != TCL_OK) { 2777 Tcl_AddErrorInfo( interp, 2778 "\n (processing -dialog option)" ); 2779 result = TCL_ERROR; 2780 goto error; 2781 } 2782 if (showDialog) { 2783 flags |= showUserSettingsDialog; 2784 } 2785 break; 2786 } 2787 2788 case kMovieFlattenOptDontInterleave: { 2789 if (Tcl_GetBooleanFromObj( interp, objv[iarg+1], 2790 &boolValue ) != TCL_OK) { 2791 Tcl_AddErrorInfo( interp, 2792 "\n (processing -dontinterleave option)" ); 2793 result = TCL_ERROR; 2794 goto error; 2795 } 2796 if (boolValue) { 2797 flags |= flattenDontInterleaveFlatten; 2798 } 2799 break; 2800 } 2801 2802 case kMovieFlattenOptForceResourceBeforeData: { 2803 if (Tcl_GetBooleanFromObj( interp, objv[iarg+1], 2804 &boolValue ) != TCL_OK) { 2805 Tcl_AddErrorInfo( interp, 2806 "\n (processing -forceresourcebeforedata option)" ); 2807 result = TCL_ERROR; 2808 goto error; 2809 } 2810 if (!boolValue) { 2811 flags &= ~flattenForceMovieResourceBeforeMovieData; 2812 } 2813 break; 2814 } 2815 } 2816 } 2817 2818 /* 2819 * Translate file name to Data Reference. 2820 */ 2821 result = QTTclNewDataRefFromUTF8Obj(interp, objv[2], 2822 &dataRef, &dataRefType); 2823 if (result != TCL_OK) { 2824 goto error; 2825 } 2826 if (showDialog || movPtr->qtvrInstance != NULL) { 2827 flags = createMovieFileDeleteCurFile | movieToFileOnlyExport | movieFileSpecValid; 2828 if (showDialog) { 2829 flags |= showUserSettingsDialog; 2830 } 2831 2832 if (movPtr->qtvrInstance != NULL) { 2833 desc.componentType = MovieExportType; 2834 desc.componentSubType = MovieFileType; 2835 desc.componentFlags = 0; 2836 desc.componentFlagsMask = 0; 2837 /* 'vrwe' */ 2838 desc.componentManufacturer = kQTVRFlattenerManufacturer; 2839 exporter = OpenComponent( FindNextComponent( NULL, &desc ) ); 2840 if (exporter == NULL) { 2841 Tcl_SetObjResult( interp, Tcl_NewStringObj( 2842 "Failed finding a QTVR flattener component", -1 ) ); 2843 result = TCL_ERROR; 2844 goto error; 2845 } 2846 } 2847 2848 // export the movie into a file 2849 // @@@ This used to return the new FSSpec but doesn't! 2850 err = ConvertMovieToDataRef(movPtr->aMovie, /* the movie */ 2851 NULL, /* all tracks */ 2852 dataRef, /* the output data reference */ 2853 dataRefType, /* the data ref type */ 2854 MovieFileType, /* output file type */ 2855 ksigMoviePlayer, /* output file creator */ 2856 flags, 2857 exporter); /* export component */ 2858 if (err == userCanceledErr) { 2859 goto error; 2860 } else if (err != noErr) { 2861 CheckAndSetErrorResult( interp, err ); 2862 result = TCL_ERROR; 2863 goto error; 2864 } 2865 obj = Tcl_NewObj(); 2866 result = QTTclNewUTF8ObjFromDataRef(interp, dataRef, dataRefType, &obj); 2867 if (result != TCL_OK) { 2868 goto error; 2869 } 2870 Tcl_SetObjResult(interp, obj); 2871 } else { 2872 Movie newMovie = FlattenMovieDataToDataRef(movPtr->aMovie, flags, 2873 dataRef, dataRefType, ksigMoviePlayer, 2874 smSystemScript, createMovieFileDeleteCurFile); 2875 if (NULL != newMovie) { 2876 // we choose not to do anything with the returned movie 2877 DisposeMovie(newMovie); 2878 } else { 2879 Tcl_SetObjResult( interp, 2880 Tcl_NewStringObj("Failed FlattenMovieDataToDataRef", -1 ) ); 2881 result = TCL_ERROR; 2882 goto error; 2883 } 2884 obj = Tcl_NewObj(); 2885 result = QTTclNewUTF8ObjFromDataRef(interp, dataRef, dataRefType, &obj); 2886 if (result != TCL_OK) { 2887 goto error; 2888 } 2889 Tcl_SetObjResult(interp, obj); 2890 } 2891 2892error: 2893 if (exporter) { 2894 CloseComponent(exporter); 2895 } 2896 if (dataRef) { 2897 DisposeHandle(dataRef); 2898 } 2899 return result; 2900} 2901 2902/* 2903 *---------------------------------------------------------------------- 2904 * 2905 * NewMovieCmd -- 2906 * 2907 * Make new movie. 2908 * 2909 * Results: 2910 * The return value is a standard Tcl result. If TCL_ERROR is 2911 * returned, then the interp's result contains an error message. 2912 * 2913 * Side effects: 2914 * New movie may be assiciated with movie widget. 2915 * 2916 *---------------------------------------------------------------------- 2917 */ 2918 2919static int 2920NewMovieCmd(Tcl_Interp *interp, 2921 int objc, Tcl_Obj *CONST objv[], 2922 MoviePlayer *movPtr) 2923{ 2924 int i; 2925 long flags; 2926 OSType dataRefType; 2927 Handle dataRef = NULL; 2928 DataHandler dataHandler = 0; 2929 Movie aMovie = movPtr->aMovie; 2930 OSErr err = noErr; 2931 int result = TCL_OK; 2932 2933 /* get rid of the old one */ 2934 RemoveMovieFromOpenMovies( movPtr ); 2935 2936 if (aMovie != NULL) { 2937 for (i = 0; i < movPtr->undoCount; i++) { 2938 DisposeMovieEditState(movPtr->editStates[i]); 2939 } 2940 movPtr->undoCount = 0; 2941 DisposeMovie( aMovie ); 2942 aMovie = NULL; 2943 gMovieRefCount--; 2944 } 2945 2946 /* 2947 * Translate file name to Data Reference. 2948 */ 2949 result = QTTclNewDataRefFromUTF8Obj(movPtr->interp, objv[2], &dataRef, &dataRefType); 2950 if (result != TCL_OK) { 2951 goto error; 2952 } 2953 flags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile; 2954 2955 /* Create a file. */ 2956 err = CreateMovieStorage(dataRef, dataRefType, ksigMoviePlayer, 2957 smCurrentScript, flags, &dataHandler, &(movPtr->aMovie)); 2958 if (err != noErr) { 2959 CheckAndSetErrorResult( interp, err ); 2960 movPtr->aMovie = NULL; 2961 result = TCL_ERROR; 2962 goto error; 2963 } 2964 aMovie = movPtr->aMovie; 2965 gMovieRefCount++; 2966 2967 /* Add the movie. */ 2968 err = AddMovieToStorage(aMovie, dataHandler); 2969 if (err != noErr) { 2970 DataHDeleteFile(dataHandler); 2971 CheckAndSetErrorResult( interp, err ); 2972 movPtr->aMovie = NULL; 2973 result = TCL_ERROR; 2974 goto error; 2975 } 2976 movPtr->resourceNumber = -1; 2977 err = CloseMovieStorage(dataHandler); 2978 2979 if (movPtr->fileNamePtr != NULL) { 2980 Tcl_DecrRefCount( movPtr->fileNamePtr ); 2981 } 2982 movPtr->fileNamePtr = objv[2]; 2983 Tcl_IncrRefCount( movPtr->fileNamePtr ); 2984 movPtr->filename = Tcl_GetString( objv[2] ); 2985 2986 Tcl_SetObjResult( interp, Tcl_NewIntObj( movPtr->resourceNumber ) ); 2987 movPtr->flags |= NEWGWORLD; 2988 2989error: 2990 /* Close the storage. */ 2991 if (dataHandler) { 2992 CloseMovieStorage(dataHandler); 2993 } 2994 if (dataRef) { 2995 DisposeHandle(dataRef); 2996 } 2997 return result; 2998} 2999 3000/* 3001 *---------------------------------------------------------------------- 3002 * 3003 * ConfigureMoviePlayer -- 3004 * 3005 * This procedure is called to process an objv/objc list, plus 3006 * the Tk option database, in order to configure (or 3007 * reconfigure) a movie player widget. Many options are set via a 3008 * movie controller so therefore it must be created just after finsished 3009 * reading the movie. 3010 * 3011 * Results: 3012 * The return value is a standard Tcl result. If TCL_ERROR is 3013 * returned, then the interp's result contains an error message. 3014 * 3015 * Side effects: 3016 * Configuration information, such as text string, colors, font, 3017 * etc. get set for movPtr; old resources get freed, if there 3018 * were any. 3019 * Only if the configuration means that a (re)display is necessary, 3020 * the NEWGWORLD flag is set. This triggers a call to 'MoviePlayerWorldChanged'. 3021 * 3022 *---------------------------------------------------------------------- 3023 */ 3024 3025static int 3026ConfigureMoviePlayer( Tcl_Interp *interp, 3027 MoviePlayer *movPtr, 3028 int objc, 3029 Tcl_Obj *CONST objv[] ) 3030{ 3031 int ierror; 3032 int i; 3033 int result = TCL_OK; 3034 int mask = 0L; 3035 long optFlags; 3036 Tcl_Obj *errorResult = NULL; 3037 Tk_SavedOptions savedOptions; 3038 OSErr err = noErr; 3039 3040 QTTclDebugPrintf( interp, 2, "ConfigureMoviePlayer" ); 3041 3042 /* 3043 * The following loop is potentially executed twice. During the 3044 * first pass configuration options get set to their new values. 3045 * If there is an error in this pass, we execute a second pass 3046 * to restore all the options to their previous values. 3047 * 3048 * A 'continue' within this loop signals an error condition; 3049 * 'break' when everything went OK. 3050 */ 3051 3052 for (ierror = 0; ierror <= 1; ierror++) { 3053 if (!ierror) { 3054 /* 3055 * First pass: set options to new values. 3056 */ 3057 3058 if (Tk_SetOptions( interp, (char *) movPtr, movPtr->optionTable, objc, 3059 objv, movPtr->tkwin, &savedOptions, &mask) != TCL_OK ) { 3060 continue; 3061 } 3062 } else { 3063 /* 3064 * Second pass: restore options to old values. 3065 */ 3066 3067 errorResult = Tcl_GetObjResult( interp ); 3068 Tcl_IncrRefCount( errorResult ); 3069 Tk_RestoreSavedOptions( &savedOptions ); 3070 } 3071 3072 /* 3073 * Check possible inconsistencies of the options. Return error if found any. 3074 * 3075 * Don't allow both file and url, at most one of them. 3076 * Tk_DestroyWindow and DestroyMovie is made in calling procedure. 3077 */ 3078 3079 if (movPtr->fileNamePtr != NULL && movPtr->url != NULL) { 3080 Tcl_SetObjResult( interp, Tcl_NewStringObj( 3081 "Does not accept both -file and -url", -1 ) ); 3082 Tk_RestoreSavedOptions( &savedOptions ); 3083 return TCL_ERROR; 3084 } 3085 3086 /* Url only with a controller. */ 3087 3088 if (movPtr->url != NULL && !movPtr->wantController) { 3089 Tcl_SetObjResult( interp, Tcl_NewStringObj( 3090 "Need a controller for -url", -1 ) ); 3091 Tk_RestoreSavedOptions( &savedOptions ); 3092 return TCL_ERROR; 3093 } 3094 3095 /* 3096 * We cannot configure a movie that is async loading and that is not yet playable. 3097 * It is configured when playable. 3098 */ 3099 3100 if ((movPtr->url != NULL) && (movPtr->state & kQTTclMovieStateAsyncLoading) && 3101 (movPtr->loadState < kMovieLoadStatePlayable)) { 3102 Tk_RestoreSavedOptions( &savedOptions ); 3103 return TCL_ERROR; 3104 } 3105 3106 Tk_SetInternalBorder( movPtr->tkwin, movPtr->highlightWidth ); 3107 if (movPtr->highlightWidth <= 0) { 3108 movPtr->highlightWidth = 0; 3109 } 3110 movPtr->inset = movPtr->padx + movPtr->highlightWidth; 3111 3112 /* 3113 * Handle the -file option. Was there a new filename? If -file {} ??? 3114 * Handle the -url option. Was there a new url? 3115 */ 3116 3117 if ((mask & MOV_CONF_FILE) || (mask & MOV_CONF_URL)) { 3118 3119 /* Get rid of the old one in the global display list. */ 3120 RemoveMovieFromOpenMovies( movPtr ); 3121 3122 /* 3123 * If there is a controller, remove since it may need a different one. 3124 */ 3125 3126 /* Old edit states not valid anymore. */ 3127 if (movPtr->aMovie != NULL) { 3128 for (i = 0; i < movPtr->undoCount; i++) { 3129 DisposeMovieEditState( movPtr->editStates[i] ); 3130 } 3131 movPtr->undoCount = 0; 3132 } 3133 3134 /* 3135 * We may have end up here during a 'configure -file newFile' call from the 3136 * '-mccommand' tcl proc, which is called from inside 'MCIsPlayerEvent'. 3137 * When we return to 'MCIsPlayerEvent' suddenly the movie doesn't exist 3138 * anymore, and the thing crashes. Wait therefore to dispose off the movie. 3139 */ 3140 3141 if (movPtr->insideMCCommand) { 3142 movPtr->tmpMovieRecordPtr = (TmpMovieRecord *) ckalloc( sizeof(TmpMovieRecord) ); 3143 movPtr->tmpMovieRecordPtr->movie = movPtr->aMovie; 3144 movPtr->tmpMovieRecordPtr->movieController = movPtr->aController; 3145 SetMovieGWorld( movPtr->aMovie, gOffscreenGWorldPtr, NULL ); 3146 movPtr->aMovie = NULL; 3147 movPtr->aController = NULL; 3148 } else { 3149 if (movPtr->aController != NULL) { 3150 DisposeMovieController( movPtr->aController ); 3151 movPtr->aController = NULL; 3152 } 3153 if (movPtr->aMovie != NULL) { 3154 DisposeMovie( movPtr->aMovie ); 3155 movPtr->aMovie = NULL; 3156 gMovieRefCount--; 3157 } 3158 } 3159 3160 /* 3161 * In case we ended up here due to a 'configure -file/-url' command, 3162 * the new movie's GWorld is not valid anymore, and the movie 3163 * should NOT be put on display until we called 'SetMovieGWorld'. 3164 */ 3165 3166 movPtr->grafPtr = NULL; 3167 movPtr->state = 0; 3168 3169 /* 3170 * Retrieve the actual movie from the specified file or url. 3171 */ 3172 3173 if (movPtr->fileNamePtr != NULL) { 3174 if ((result = GetMovie( movPtr )) != TCL_OK) { 3175 continue; 3176 } 3177 } else if (movPtr->url != NULL) { 3178 if ((result = GetMovieFromUrl( movPtr )) != TCL_OK) { 3179 continue; 3180 } 3181 } 3182 3183 /* 3184 * Whenever we open a new movie put it offscreen unitil we 3185 * display it. 3186 */ 3187 3188 SetMovieGWorld( movPtr->aMovie, gOffscreenGWorldPtr, NULL ); 3189 movPtr->flags |= NEWGWORLD; 3190 } 3191 3192 /* 3193 * Set no progress procedure, QuickTime default, or a tcl procedure. 3194 */ 3195 3196 if (mask & MOV_CONF_PROGRESS_PROC) { 3197 if (movPtr->progressProc != NULL) { 3198#if TARGET_API_MAC_CARBON 3199 SetMovieProgressProc( movPtr->aMovie, NewMovieProgressUPP(MovieProgressFunction), 3200 (long) movPtr ); 3201#else 3202 SetMovieProgressProc( movPtr->aMovie, NewMovieProgressProc(MovieProgressFunction), 3203 (long) movPtr ); 3204#endif 3205 } else if (movPtr->qtprogress) { 3206 SetMovieProgressProc( movPtr->aMovie, (MovieProgressUPP) -1, 0 ); 3207 } else { 3208 SetMovieProgressProc( movPtr->aMovie, NULL, 0 ); 3209 } 3210 } 3211 3212 /* 3213 * Attach any controller. Many of the configure options need a controller to work, 3214 * and therefore we cannot wait to make the controller until it is displayed. 3215 * If we write 'movie .m', the controller is not added here, but later in 3216 * 'MoviePlayerWorldChanged,. 3217 */ 3218 3219 AddOrRemoveMovieController( movPtr ); 3220 3221 /* 3222 * Do we need to set the controllers edit state? Be sure to also set 3223 * the controller callback function to make movie and track selection 3224 * mutually exclusive. 3225 */ 3226 3227 if ((movPtr->aController != NULL) && (mask & MOV_CONF_MCEDIT)) { 3228 if (movPtr->mcEdit) { 3229 MCEnableEditing( movPtr->aController, true ); 3230#if TARGET_API_MAC_CARBON 3231 MCSetActionFilterWithRefCon( movPtr->aController, 3232 NewMCActionFilterWithRefConUPP( MovieControllerCallbackFunction ), 3233 (long) movPtr ); 3234#else 3235 MCSetActionFilterWithRefCon( movPtr->aController, 3236 NewMCActionFilterWithRefConProc( MovieControllerCallbackFunction ), 3237 (long) movPtr ); 3238#endif 3239 } else { 3240 MCEnableEditing( movPtr->aController, false ); 3241 } 3242 MCMovieChanged( movPtr->aController, movPtr->aMovie ); 3243 } 3244 3245 /* 3246 * Set the loopstates if any. Set only if different from old state. 3247 */ 3248 3249 if (mask & MOV_CONF_LOOPSTATE) { 3250 if (movPtr->aMovie != NULL) { 3251 if (movPtr->aController != NULL) { 3252 MCDoAction( movPtr->aController, mcActionSetLooping, 3253 (void *) movPtr->loopstate ); 3254 MCDoAction( movPtr->aController, mcActionSetLoopIsPalindrome, 3255 (void *) false ); 3256 } else { 3257 if (movPtr->loopstate) { 3258 SetMovieLoopState( movPtr->aMovie, kQTTclNormalLooping ); 3259 } else { 3260 SetMovieLoopState( movPtr->aMovie, kQTTclNoLooping ); 3261 } 3262 } 3263 } else { 3264 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 3265 continue; 3266 } 3267 } 3268 if (mask & MOV_CONF_PALINDROME_LOOPSTATE) { 3269 if (movPtr->aMovie != NULL) { 3270 if (movPtr->aController != NULL) { 3271 if (movPtr->palindromeloopstate) { 3272 SetLoopingState( movPtr->aController, kQTTclPalindromeLooping ); 3273 } else { 3274 SetLoopingState( movPtr->aController, kQTTclNoLooping ); 3275 } 3276 } else { 3277 if (movPtr->palindromeloopstate) { 3278 SetMovieLoopState( movPtr->aMovie, kQTTclPalindromeLooping ); 3279 } else { 3280 SetMovieLoopState( movPtr->aMovie, kQTTclNoLooping ); 3281 } 3282 } 3283 } else { 3284 Tcl_SetObjResult( interp, Tcl_NewStringObj( "No movie", -1 ) ); 3285 continue; 3286 } 3287 } 3288 3289 /* 3290 * Set the movie's volume if changed. If user interactively changes the volume, 3291 * we cannot detect this. 3292 * The 'MCMovieChanged' updates the volume button in the controller. 3293 */ 3294 3295 if ((movPtr->aMovie != NULL) && (mask & MOV_CONF_VOLUME)) { 3296 SetMovieVolume( movPtr->aMovie, (short) movPtr->volume ); 3297 if (movPtr->aController != NULL) { 3298 MCMovieChanged( movPtr->aController, movPtr->aMovie ); 3299 } 3300 } 3301 3302 /* 3303 * Set movie's preferred play rate. 3304 */ 3305 3306 if ((movPtr->aMovie != NULL) && (mask & MOV_CONF_PREFERRED_RATE)) { 3307 SetMoviePreferredRate( movPtr->aMovie, X2Fix( movPtr->preferredRate ) ); 3308 } 3309 3310 /* 3311 * Here we set any callback function for the movie controller so that 3312 * a tcl procedure can monitor user actions. 3313 * It is also necessary if we allow resizing via the controller. 3314 */ 3315 3316 if ((movPtr->aMovie != NULL) && (movPtr->aController != NULL) && 3317 ((movPtr->mcCallbackProc != NULL) || movPtr->resizable)) { 3318#if TARGET_API_MAC_CARBON 3319 MCSetActionFilterWithRefCon( movPtr->aController, 3320 NewMCActionFilterWithRefConUPP( MovieControllerCallbackFunction ), 3321 (long) movPtr ); 3322#else 3323 MCSetActionFilterWithRefCon( movPtr->aController, 3324 NewMCActionFilterWithRefConProc( MovieControllerCallbackFunction ), 3325 (long) movPtr ); 3326#endif 3327 } 3328 3329 /* 3330 * Get the QTVR instance for QTVR panos. Returns NULL for non QTVR movies. 3331 * Special configuration for QTVR movies. 3332 */ 3333 3334 if ((movPtr->aMovie != NULL) && (movPtr->aController != NULL) && 3335 IsQTVRMovie( movPtr->aMovie )) { 3336 movPtr->qtvrInstance = GetQTVRInstanceFromController( movPtr->aController ); 3337 if (movPtr->qtvrInstance != NULL) { 3338 ConfigureQTVRMovie( interp, movPtr, 3339 mask & MOV_CONF_QTVR_QUALITY_STATIC, 3340 mask & MOV_CONF_QTVR_QUALITY_MOTION ); 3341 } 3342 } 3343 3344 /* 3345 * Is there a custom button in the movie controller bar? 3346 */ 3347 3348 if ((movPtr->aController != NULL) && (mask & MOV_CONF_CUSTOM_BUTTON)) { 3349 if (movPtr->custombutton) { 3350 ShowControllerButton( movPtr->aController, mcFlagsUseCustomButton ); 3351 } else { 3352 HideControllerButton( movPtr->aController, mcFlagsUseCustomButton ); 3353 } 3354 MCMovieChanged( movPtr->aController, movPtr->aMovie ); 3355 } 3356 3357 /* 3358 * Do we want the movie to be resizable via the controller. 3359 */ 3360 3361 if ((movPtr->aController != NULL) && (mask & MOV_CONF_RESIZEABLE)) { 3362 Rect r; 3363 3364#if TARGET_API_MAC_CARBON 3365 MacSetRect( &r, 0, 0, 2000, 1800 ); 3366#else 3367 { 3368 CGrafPtr wmPortPtr = NULL; 3369 3370 GetCWMgrPort( &wmPortPtr ); 3371 r = wmPortPtr->portRect; 3372 } 3373#endif 3374 if (movPtr->resizable) { 3375 MCDoAction( movPtr->aController, mcActionSetGrowBoxBounds, &r ); 3376 } else { 3377 MacSetRect( &r, 0, 0, 0, 0 ); 3378 MCDoAction( movPtr->aController, mcActionSetGrowBoxBounds, &r ); 3379 } 3380 MCMovieChanged( movPtr->aController, movPtr->aMovie ); 3381 } 3382 3383 /* 3384 * Loading a remote movie into ram is unpredictable. 3385 */ 3386 3387 if ((movPtr->aMovie != NULL) && (movPtr->url == NULL) && 3388 (mask & MOV_CONF_LOAD_INTO_RAM)) { 3389 if (movPtr->loadIntoRam) { 3390 optFlags = keepInRam; 3391 } else { 3392 optFlags = unkeepInRam; 3393 } 3394 err = LoadMovieIntoRam( movPtr->aMovie, 0, 3395 GetMovieDuration(movPtr->aMovie), optFlags ); 3396 if (err != noErr) { 3397 CheckAndSetErrorResult( movPtr->interp, noErr ); 3398 return TCL_ERROR; 3399 } 3400 } 3401 3402 /* 3403 * Changing any of the -highlight* needs a redisplay. 3404 */ 3405 3406 if (mask & MOV_CONF_HIGHLIGHTS) { 3407 movPtr->flags |= NEWGWORLD; 3408 } 3409 3410 /* 3411 * If we came so far break out of the ierror loop. 3412 */ 3413 3414 break; 3415 } 3416 3417 if (ierror) { 3418 Tcl_SetObjResult(interp, errorResult); 3419 Tcl_DecrRefCount(errorResult); 3420 return TCL_ERROR; 3421 } else { 3422 /* 3423 * If width or height changed, reschedule a new display. 3424 */ 3425 3426 if (mask & MOV_CONF_NEWGWORLD) { 3427 movPtr->flags |= NEWGWORLD; 3428 } 3429 Tk_FreeSavedOptions( &savedOptions ); 3430 return TCL_OK; 3431 } 3432} 3433 3434/* 3435 *---------------------------------------------------------------------- 3436 * 3437 * ConfigureQTVRMovie -- 3438 * 3439 * Processes the QTVR specific options. 3440 * 3441 * Results: 3442 * The return value is a standard Tcl result. If TCL_ERROR is 3443 * returned, then the interp's result contains an error message. 3444 * 3445 * Side effects: 3446 * Movie settings may be changed. 3447 * 3448 *---------------------------------------------------------------------- 3449 */ 3450 3451static int 3452ConfigureQTVRMovie( Tcl_Interp *interp, 3453 MoviePlayer * movPtr, 3454 int setQTVRQualityStatic, 3455 int setQTVRQualityMotion ) 3456{ 3457 int result = TCL_OK; 3458 SInt32 propertyValue; 3459 3460 if (!IsQTVRMovie( movPtr->aMovie )) { 3461 return result; 3462 } 3463 if (movPtr->qtvrInstance == NULL) { 3464 return result; 3465 } 3466 3467 /* 3468 * In QTVR panos we doesn't want tk to set our cursor. Doesn't work! 3469 * Handle quality settings. 3470 */ 3471 3472 Tk_UndefineCursor( movPtr->tkwin ); 3473 3474 if (movPtr->indQTVRQualityStatic == -1) { 3475 3476 /* First time: */ 3477 3478 QTVRGetImagingProperty( movPtr->qtvrInstance, kQTVRStatic, kQTVRImagingQuality, 3479 &propertyValue ); 3480 if (propertyValue == codecMinQuality) { 3481 movPtr->indQTVRQualityStatic = MOV_QTVR_QUALITY_MIN; 3482 } else if (propertyValue == codecLowQuality) { 3483 movPtr->indQTVRQualityStatic = MOV_QTVR_QUALITY_LOW; 3484 } else if (propertyValue == codecNormalQuality) { 3485 movPtr->indQTVRQualityStatic = MOV_QTVR_QUALITY_NORMAL; 3486 } else if (propertyValue == codecHighQuality) { 3487 movPtr->indQTVRQualityStatic = MOV_QTVR_QUALITY_HIGH; 3488 } else if (propertyValue == codecMaxQuality) { 3489 movPtr->indQTVRQualityStatic = MOV_QTVR_QUALITY_MAX; 3490 } 3491 } else if (setQTVRQualityStatic) { 3492 3493 /* User configured this one: */ 3494 3495 switch (movPtr->indQTVRQualityStatic) { 3496 case MOV_QTVR_QUALITY_MIN: { 3497 propertyValue = codecMinQuality; 3498 break; 3499 } 3500 case MOV_QTVR_QUALITY_LOW: { 3501 propertyValue = codecLowQuality; 3502 break; 3503 } 3504 case MOV_QTVR_QUALITY_NORMAL: { 3505 propertyValue = codecNormalQuality; 3506 break; 3507 } 3508 case MOV_QTVR_QUALITY_HIGH: { 3509 propertyValue = codecHighQuality; 3510 break; 3511 } 3512 case MOV_QTVR_QUALITY_MAX: { 3513 propertyValue = codecMaxQuality; 3514 break; 3515 } 3516 } 3517 QTVRSetImagingProperty( movPtr->qtvrInstance, kQTVRStatic, kQTVRImagingQuality, 3518 propertyValue ); 3519 } 3520 3521 if (movPtr->indQTVRQualityMotion == -1) { 3522 3523 /* First time: */ 3524 3525 QTVRGetImagingProperty( movPtr->qtvrInstance, kQTVRMotion, kQTVRImagingQuality, 3526 &propertyValue ); 3527 if (propertyValue == codecMinQuality) { 3528 movPtr->indQTVRQualityMotion = MOV_QTVR_QUALITY_MIN; 3529 } else if (propertyValue == codecLowQuality) { 3530 movPtr->indQTVRQualityMotion = MOV_QTVR_QUALITY_LOW; 3531 } else if (propertyValue == codecNormalQuality) { 3532 movPtr->indQTVRQualityMotion = MOV_QTVR_QUALITY_NORMAL; 3533 } else if (propertyValue == codecHighQuality) { 3534 movPtr->indQTVRQualityMotion = MOV_QTVR_QUALITY_HIGH; 3535 } else if (propertyValue == codecMaxQuality) { 3536 movPtr->indQTVRQualityMotion = MOV_QTVR_QUALITY_MAX; 3537 } 3538 } else if (setQTVRQualityMotion) { 3539 3540 /* User configured this one: */ 3541 3542 switch (movPtr->indQTVRQualityMotion) { 3543 case MOV_QTVR_QUALITY_MIN: { 3544 propertyValue = codecMinQuality; 3545 break; 3546 } 3547 case MOV_QTVR_QUALITY_LOW: { 3548 propertyValue = codecLowQuality; 3549 break; 3550 } 3551 case MOV_QTVR_QUALITY_NORMAL: { 3552 propertyValue = codecNormalQuality; 3553 break; 3554 } 3555 case MOV_QTVR_QUALITY_HIGH: { 3556 propertyValue = codecHighQuality; 3557 break; 3558 } 3559 case MOV_QTVR_QUALITY_MAX: { 3560 propertyValue = codecMaxQuality; 3561 break; 3562 } 3563 } 3564 QTVRSetImagingProperty( movPtr->qtvrInstance, kQTVRMotion, kQTVRImagingQuality, 3565 propertyValue ); 3566 } 3567 3568 /* 3569 * Callback function for QTVR movies. 3570 */ 3571 3572 if ((movPtr->aController != NULL) && (movPtr->mcCallbackProc != NULL)) { 3573 3574#if TARGET_API_MAC_CARBON 3575 movPtr->funcQTVRIntercept = NewQTVRInterceptUPP( MyQTVRInterceptProc ); 3576#else 3577 movPtr->funcQTVRIntercept = NewQTVRInterceptProc( MyQTVRInterceptProc ); 3578#endif 3579 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetPanAngleSelector, 3580 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3581 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetTiltAngleSelector, 3582 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3583 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetFieldOfViewSelector, 3584 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3585 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRTriggerHotSpotSelector, 3586 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3587 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseDownSelector, 3588 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3589 /* 3590 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseEnterSelector, 3591 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3592 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseLeaveSelector, 3593 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3594 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRGetHotSpotTypeSelector, 3595 movPtr->funcQTVRIntercept, (long) movPtr, 0 ); 3596 */ 3597 } else { 3598 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetPanAngleSelector, NULL, 0, 0 ); 3599 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetTiltAngleSelector, NULL, 0, 0 ); 3600 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRSetFieldOfViewSelector, NULL, 0, 0 ); 3601 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseEnterSelector, NULL, 0, 0 ); 3602 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseLeaveSelector, NULL, 0, 0 ); 3603 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRTriggerHotSpotSelector, NULL, 0, 0 ); 3604 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRGetHotSpotTypeSelector, NULL, 0, 0 ); 3605 QTVRInstallInterceptProc( movPtr->qtvrInstance, kQTVRMouseDownSelector, NULL, 0, 0 ); 3606#if TARGET_API_MAC_CARBON 3607 DisposeQTVRInterceptUPP( movPtr->funcQTVRIntercept ); 3608#else 3609 DisposeRoutineDescriptor( movPtr->funcQTVRIntercept ); 3610#endif 3611 movPtr->funcQTVRIntercept = NULL; 3612 } 3613 if (movPtr->swing) { 3614 QTVREnableTransition( movPtr->qtvrInstance, kQTVRTransitionSwing, true ); 3615 } else { 3616 QTVREnableTransition( movPtr->qtvrInstance, kQTVRTransitionSwing, false ); 3617 } 3618 3619 /* Verify that the speed is an integer between 1 and 10. */ 3620 if (movPtr->swingSpeed < 1) { 3621 movPtr->swingSpeed = 1; 3622 } else if (movPtr->swingSpeed > 10) { 3623 movPtr->swingSpeed = 10; 3624 } 3625 QTVRSetTransitionProperty( movPtr->qtvrInstance, kQTVRTransitionSwing, 3626 kQTVRTransitionSpeed, movPtr->swingSpeed ); 3627 QTVRSetTransitionProperty( movPtr->qtvrInstance, kQTVRTransitionSwing, 3628 kQTVRTransitionDirection, -1 ); 3629 3630 return result; 3631} 3632 3633/* 3634 *---------------------------------------------------------------------- 3635 * 3636 * GetMovie -- 3637 * 3638 * Get a Movie given a filename, all info is stored in movPtr. 3639 * 3640 * Results: 3641 * Normal TCL. 3642 * 3643 * Side effects: 3644 * Movie Allocated 3645 * 3646 *---------------------------------------------------------------------- 3647 */ 3648 3649static int 3650GetMovie( MoviePlayer *movPtr ) 3651{ 3652 OSErr err = noErr; 3653 Rect aRect; 3654 Fixed thePlayRate; 3655 short resId = 0; 3656 int result = TCL_OK; 3657 OSType dataRefType; 3658 Handle dataRef = NULL; 3659 3660 QTTclDebugPrintf( movPtr->interp, 2, "GetMovie" ); 3661 3662 /* 3663 * Translate file name to Data Reference. 3664 */ 3665 result = QTTclNewDataRefFromUTF8Obj(movPtr->interp, movPtr->fileNamePtr, 3666 &dataRef, &dataRefType); 3667 if (result != TCL_OK) { 3668 result = TCL_ERROR; 3669 goto bail; 3670 } 3671 err = NewMovieFromDataRef(&(movPtr->aMovie), newMovieActive, 3672 &resId, dataRef, dataRefType); 3673 if (err != noErr) { 3674 CheckAndSetErrorResult( movPtr->interp, err ); 3675 result = TCL_ERROR; 3676 goto bail; 3677 } 3678 QTTclDebugPrintf( movPtr->interp, 2, "\taMovie=%d", movPtr->aMovie ); 3679 3680 movPtr->resourceNumber = resId; 3681 gMovieRefCount++; 3682 3683 /* This disables the movie so it wont play and wont show up. */ 3684 //SetMovieActive( movPtr->aMovie, false ); // gives no sound sometimes 3685 SetMovieActive( movPtr->aMovie, true ); 3686 3687 /* The movies natural size without any controller, and a few other options */ 3688 GetMovieBox( movPtr->aMovie, &aRect ); 3689 movPtr->mwidth = aRect.right - aRect.left; 3690 movPtr->mheight = aRect.bottom - aRect.top; 3691 thePlayRate = GetMoviePreferredRate( movPtr->aMovie ); 3692 movPtr->preferredRate = Fix2X( thePlayRate ); 3693 if (movPtr->volume == 255) { 3694 movPtr->volume = GetMoviePreferredVolume( movPtr->aMovie ); 3695 } 3696 3697 /* 3698 * -1 sets the default progress, NULL removes any progress dialog. 3699 */ 3700 SetMovieProgressProc( movPtr->aMovie, (MovieProgressUPP) -1L, 0 ); 3701 3702bail: 3703 if (dataRef) { 3704 DisposeHandle(dataRef); 3705 } 3706 return result; 3707} 3708 3709/* 3710 *---------------------------------------------------------------------- 3711 * 3712 * GetMovieFromUrl -- 3713 * 3714 * Get a Movie from the url (stored in movPtr). 3715 * 3716 * Results: 3717 * Normal TCL. 3718 * 3719 * Side effects: 3720 * Movie allocated. 3721 * 3722 *---------------------------------------------------------------------- 3723 */ 3724 3725static int 3726GetMovieFromUrl( MoviePlayer *movPtr ) 3727{ 3728 char *charPtr; 3729 int len = 0; 3730 short flags = 0; 3731 Tcl_DString ds; 3732 Rect aRect; 3733 Handle urlDataRef = NULL; 3734 CGrafPtr oldPort = NULL; 3735 GDHandle oldGDeviceH = NULL; 3736 QDErr err = noErr; 3737 int result = TCL_OK; 3738 3739 QTTclDebugPrintf( movPtr->interp, 2, "GetMovieFromUrl" ); 3740 3741 if (strlen(movPtr->url) == 0) { 3742 Tcl_SetObjResult( movPtr->interp, Tcl_NewStringObj( 3743 "URL of zero length not valid", -1 ) ); 3744 result = TCL_ERROR; 3745 goto bail; 3746 } 3747 3748 charPtr = Tcl_UtfToExternalDString( gQTTclTranslationEncoding, movPtr->url, -1, &ds); 3749 len = Tcl_DStringLength( &ds ); 3750 urlDataRef = MySafeNewHandle( len + 1, 1 ); 3751 BlockMoveData( charPtr, *urlDataRef, len ); 3752 3753 /* 3754 * Fetch the movie. In blocking mode if no 'loadCommand', 3755 * else async. Need to use 'gMoviePlayerListPtr' and the state member to serve 3756 * it while loading. Note: async movie must? be active to be served? yes. 3757 */ 3758 3759 movPtr->resourceNumber = -1; 3760 GetGWorld( &oldPort, &oldGDeviceH ); 3761 SetGWorld( gOffscreenGWorldPtr, NULL ); 3762 3763 if (movPtr->loadCommand != NULL) { 3764 flags = newMovieActive | newMovieAsyncOK; 3765 } else { 3766 flags = newMovieActive; 3767 } 3768 3769 err = NewMovieFromDataRef( &(movPtr->aMovie), flags, NULL, urlDataRef, 3770 URLDataHandlerSubType ); 3771 if (err != noErr) { 3772 CheckAndSetErrorResult( movPtr->interp, err ); 3773 result = TCL_ERROR; 3774 goto bail; 3775 } 3776 gMovieRefCount++; 3777 if (movPtr->loadCommand != NULL) { 3778 3779 /* The movie should be served, with 'MoviesTask', but not displayed. */ 3780 movPtr->state |= kQTTclMovieStateAsyncLoading; 3781 } else { 3782 3783 /* Set the rect to the movies natural size. */ 3784 GetMovieBox( movPtr->aMovie, &aRect ); 3785 movPtr->mwidth = aRect.right - aRect.left; 3786 movPtr->mheight = aRect.bottom - aRect.top; 3787 } 3788 3789bail: 3790 3791 if (urlDataRef != NULL) { 3792 DisposeHandle( urlDataRef ); 3793 } 3794 Tcl_DStringFree( &ds ); 3795 SetGWorld( oldPort, oldGDeviceH ); 3796 return result; 3797} 3798 3799/* 3800 *---------------------------------------------------------------------- 3801 * 3802 * MovieProgressFunction -- 3803 * 3804 * Called by the Movie Toolbox when there is a long operation. 3805 * 3806 * Results: 3807 * Mac Error Codes 3808 * 3809 * Side effects: 3810 * Tcl command may be run. 3811 * 3812 *---------------------------------------------------------------------- 3813 */ 3814 3815static pascal OSErr 3816MovieProgressFunction( Movie theMovie, short message, short whatOperation, 3817 Fixed percentDone, long refcon ) 3818{ 3819 MoviePlayer *movPtr = (MoviePlayer *) refcon; 3820 int result = TCL_OK; 3821 char cmd[255]; 3822 char percent[255]; 3823 3824 if (movPtr->progressProc != NULL) { 3825 strcpy( cmd, movPtr->progressProc ); 3826 strcat( cmd, " " ); 3827 strcat( cmd, Tcl_GetCommandName( movPtr->interp, movPtr->widgetCmd ) ); 3828 3829 switch (message) { 3830 case movieProgressOpen: { 3831 strcat(cmd, " open"); 3832 break; 3833 } 3834 case movieProgressUpdatePercent: { 3835 strcat(cmd, " percent"); 3836 break; 3837 } 3838 case movieProgressClose: { 3839 strcat(cmd, " close"); 3840 break; 3841 } 3842 default: 3843 strcat(cmd, " other"); 3844 } 3845 3846 switch (whatOperation) { 3847 case progressOpFlatten: { 3848 strcat(cmd, " flatten"); 3849 break; 3850 } 3851 case progressOpInsertTrackSegment: { 3852 strcat(cmd, " insertTrackSegment"); 3853 break; 3854 } 3855 case progressOpInsertMovieSegment: { 3856 strcat(cmd, " insertMovieSegment"); 3857 break; 3858 } 3859 case progressOpPaste: { 3860 strcat(cmd, " paste"); 3861 break; 3862 } 3863 case progressOpAddMovieSelection: { 3864 strcat(cmd, " addMovieSelection"); 3865 break; 3866 } 3867 case progressOpCopy: { 3868 strcat(cmd, " copy"); 3869 break; 3870 } 3871 case progressOpCut: { 3872 strcat(cmd, " cut"); 3873 break; 3874 } 3875 case progressOpLoadMovieIntoRam: { 3876 strcat(cmd, " loadMovieIntoRam"); 3877 break; 3878 } 3879 case progressOpLoadTrackIntoRam: { 3880 strcat(cmd, " loadTrackIntoRam"); 3881 break; 3882 } 3883 case progressOpLoadMediaIntoRam: { 3884 strcat(cmd, " loadMediaIntoRam"); 3885 break; 3886 } 3887 case progressOpImportMovie: { 3888 strcat(cmd, " importMovie"); 3889 break; 3890 } 3891 case progressOpExportMovie: { 3892 strcat(cmd, " exportMovie"); 3893 break; 3894 } 3895 default: { 3896 strcat(cmd, " other"); 3897 } 3898 } 3899 3900 sprintf( percent, " %ld", Fix2Long( FixMul( Long2Fix(100), percentDone ) ) ); 3901 strcat( cmd, percent ); 3902 result = Tcl_Eval( movPtr->interp, cmd ); 3903 } 3904 // This seems to create infinite loop in some circumstances!!! 3905 Tcl_DoOneEvent( TCL_DONT_WAIT | TCL_ALL_EVENTS ); 3906 3907 if (result != TCL_OK) { 3908 3909 /* 3910 * Whenever the tcl procedure returns anything else than TCL_OK, this should 3911 * trigger a cancellation of the job. A press to a cancel button should return, 3912 * for instance, a 'break' code (return -code 3). 3913 */ 3914 3915 return userCanceledErr; 3916 } else { 3917 return noErr; 3918 } 3919} 3920 3921/* 3922 *---------------------------------------------------------------------- 3923 * 3924 * MovieControllerCallbackFunction -- 3925 * 3926 * Called by the Movie Controller when there is an action. 3927 * 3928 * Results: 3929 * Mac Error Codes 3930 * 3931 * Side effects: 3932 * Tcl command may be run, or 3933 * 3934 *---------------------------------------------------------------------- 3935 */ 3936 3937static pascal Boolean 3938MovieControllerCallbackFunction( MovieController mc, 3939 short action, 3940 void *params, 3941 long refCon ) 3942{ 3943 MoviePlayer *movPtr = (MoviePlayer *) refCon; 3944 Tcl_Interp *interp = movPtr->interp; 3945 Movie saveMovie = NULL; 3946 MovieController saveController = NULL; 3947 Rect myMovieBounds; 3948 int result = TCL_OK; 3949 int width, height; 3950 int prevWidth, prevHeight; 3951 Boolean isHandled = false; 3952 Boolean isResized; 3953 Point aPoint; 3954 Rect aRect; 3955 TimeRecord *timePtr; 3956 UInt32 aMessage; 3957 char cmd[255]; 3958 char strPara[255]; 3959 3960 if ((action == mcActionIdle) || (movPtr->aMovie == NULL)) { 3961 return isHandled; 3962 } 3963 3964 /* 3965 * Signals that we does not exist anymore. 3966 */ 3967 3968 if (movPtr->flags & MOVIE_DELETED) { 3969 return isHandled; 3970 } 3971 3972 /* 3973 * We shall not call the tcl proc recursively since this screws up any idle calls 3974 * on exiting this function. 3975 */ 3976 3977 if (movPtr->insideMCCommand) { 3978 return isHandled; 3979 } 3980 QTTclDebugPrintf( movPtr->interp, 4, "MovieControllerCallbackFunction enter" ); 3981 3982 Tcl_Preserve( (ClientData) movPtr ); 3983 saveMovie = movPtr->aMovie; 3984 saveController = movPtr->aController; 3985 3986 /* 3987 * We can have either a tcl procedure or resizing via the controller or both. 3988 */ 3989 3990 if (movPtr->resizable && (action == mcActionControllerSizeChanged) && 3991 !(movPtr->flags & REDRAW_PENDING)) { 3992 MCGetControllerBoundsRect( movPtr->aController, &myMovieBounds ); 3993 width = myMovieBounds.right - myMovieBounds.left; 3994 height = myMovieBounds.bottom - myMovieBounds.top; 3995 3996 /* 3997 * This procedure gets called, for instance, on the initial display, and we 3998 * must figure out if the size actually changed before requesting a new size. 3999 */ 4000 4001 if (movPtr->width == 0) { 4002 prevWidth = movPtr->mwidth; 4003 } else { 4004 prevWidth = movPtr->width; 4005 } 4006 if (movPtr->height == 0) { 4007 prevHeight = movPtr->mheight + movPtr->controllerHeight; 4008 } else { 4009 prevHeight = movPtr->height; 4010 } 4011 if ((prevWidth != width) || (prevHeight != height)) { 4012 isResized = true; 4013 } else { 4014 isResized = false; 4015 } 4016 4017 QTTclDebugPrintf( interp, 2, "\taction=%d, width=%d, height=%d, isResized=%d", 4018 action, width, height, isResized ); 4019 4020 /* 4021 * We try to make an immediate resize here. The size is changed before this 4022 * procedure returns. Schedule for a redisplay to tell tk as well. 4023 */ 4024 4025 Tk_ResizeWindow( movPtr->tkwin, width, height ); 4026 4027 /* 4028 * Need to set the width and height elements if resized interactively, but not 4029 * if the user has 'configure'ed us to any width = 0, or height = 0. 4030 */ 4031 4032 if (width != movPtr->mwidth) { 4033 movPtr->width = width; 4034 } 4035 if (height != movPtr->mheight + movPtr->controllerHeight) { 4036 movPtr->height = height; 4037 } 4038 4039 if (isResized) { 4040 movPtr->flags |= NEWGWORLD; 4041 movPtr->flags |= UPDATEMOVIE; 4042 MoviePlayerWorldChanged( (ClientData) movPtr ); 4043 } 4044 } 4045 4046 /* 4047 * If we have '-mcedit' enabled, any selection must invalidate any track selection. 4048 */ 4049 4050 if (movPtr->mcEdit && ( (action == mcActionSetSelectionBegin) || 4051 (action == mcActionSetSelectionDuration) )) { 4052 movPtr->trackSelect->trackID = 0; 4053 } 4054 4055 /* 4056 * Catch the event, get any parameters, and call the registered tcl callback procedure. 4057 * 'ProcName widget action {parameter}' 4058 */ 4059 4060 if (movPtr->mcCallbackProc != NULL) { 4061 CGrafPtr saveWorld = NULL; 4062 GDHandle saveDevice = NULL; 4063 GWorldPtr destPort = NULL; 4064 //Tcl_Obj *listObjPtr; 4065 4066 /* 4067 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 4068 Tcl_ListObjAppendElement( interp, listObjPtr, 4069 Tcl_NewStringObj(movPtr->mcCallbackProc, -1) ); 4070 */ 4071 strcpy( cmd, movPtr->mcCallbackProc ); 4072 strcat( cmd, " " ); 4073 strcat( cmd, Tcl_GetCommandName(interp, movPtr->widgetCmd) ); 4074 4075 switch (action) { 4076 case mcActionActivate: { 4077 strcat(cmd, " activate"); 4078 break; 4079 } 4080 case mcActionCustomButtonClick: { 4081 strcat(cmd, " customButtonClick"); 4082 aPoint = ((EventRecord *) params)->where; 4083 LocalToGlobal( &aPoint ); 4084 sprintf( strPara, " {%d %d}", aPoint.h, aPoint.v ); 4085 strcat(cmd, strPara); 4086 isHandled = true; 4087 break; 4088 } 4089 case mcActionDeactivate: { 4090 strcat(cmd, " deactivate"); 4091 break; 4092 } 4093 case mcActionGoToTime: { 4094 timePtr = (TimeRecord *) params; 4095 strcat(cmd, " goToTime" ); 4096 sprintf( strPara, " {%d %d %d}", 4097 (int) timePtr->value.hi, (int) timePtr->value.lo, (int) timePtr->scale ); 4098 strcat( cmd, strPara ); 4099 break; 4100 } 4101 case mcActionKey: { 4102 strcat(cmd, " key"); 4103 aMessage = ((EventRecord *) params)->message; 4104 sprintf( strPara, " %c", (int) aMessage & charCodeMask ); 4105 strcat(cmd, strPara); 4106 break; 4107 } 4108 case mcActionMouseDown: { 4109 strcat(cmd, " mouseDown"); 4110 aPoint = ((EventRecord *) params)->where; 4111 LocalToGlobal( &aPoint ); 4112 sprintf( strPara, " {%d %d}", aPoint.h, aPoint.v ); 4113 strcat(cmd, strPara); 4114 break; 4115 } 4116 case mcActionPlay: { 4117 strcat(cmd, " play"); 4118 sprintf( strPara, " %f", Fix2X((Fixed) params) ); 4119 strcat( cmd, strPara ); 4120 break; 4121 } 4122 case mcActionSetSelectionBegin: { 4123 timePtr = (TimeRecord *) params; 4124 strcat(cmd, " setSelectionBegin"); 4125 sprintf( strPara, " %li", timePtr->value.lo ); 4126 strcat( cmd, strPara ); 4127 break; 4128 } 4129 case mcActionSetSelectionDuration: { 4130 timePtr = (TimeRecord *) params; 4131 strcat(cmd, " setSelectionDuration"); 4132 sprintf( strPara, " %li", timePtr->value.lo ); 4133 strcat( cmd, strPara ); 4134 break; 4135 } 4136 case mcActionSetVolume: { 4137 strcat(cmd, " setVolume"); 4138 sprintf( strPara, " %li", ((EventRecord *) params)->message ); 4139 strcat( cmd, strPara ); 4140 break; 4141 } 4142 default: 4143 goto bail; 4144 } 4145 4146 /* 4147 * Perform the actual action. Any 'update' command in the tcl procedure 4148 * ruins update events sent to redraw the controller, and we must therefore 4149 * invalidate, make dirty, the controller rectangle! 4150 * Beware, we may have been destroyed in the callback! 4151 */ 4152 4153 movPtr->insideMCCommand++; 4154 result = Tcl_Eval( interp, cmd ); 4155 movPtr->insideMCCommand--; 4156 4157 if (movPtr->flags & MOVIE_DELETED) { 4158 isHandled = true; 4159 goto bail; 4160 } 4161 4162 GetGWorld( &saveWorld, &saveDevice ); 4163 GetMovieGWorld( saveMovie, &destPort, NULL ); 4164 SetGWorld( destPort, NULL ); 4165 MCGetControllerBoundsRect( saveController, &aRect ); 4166 aRect.top = aRect.bottom - movPtr->controllerHeight; 4167#if TARGET_API_MAC_CARBON 4168 // This seems to create infinite loop in some circumstances!!! 4169 //Tcl_DoOneEvent( TCL_DONT_WAIT | TCL_ALL_EVENTS ); 4170 InvalWindowRect( GetWindowFromPort(destPort), &aRect ); 4171#else 4172 InvalRect( &aRect ); 4173#endif 4174 SetGWorld( saveWorld, saveDevice ); 4175 4176 /* 4177 * If the original movie was destroyed or configure -file, then we put the 4178 * destruction as an idle call so that we don't crash. 4179 */ 4180 4181 if (movPtr->tmpMovieRecordPtr != NULL) { 4182 Tcl_DoWhenIdle( DisposeMovieAtIdle, (ClientData) movPtr ); 4183 } 4184 } 4185 4186 /* 4187 * We should return false to indicate that we only monitor the events here, 4188 * except if the callback script changed our movie (with configure -file), 4189 * or if script returned TCL_BREAK (break). 4190 */ 4191 4192 if ((saveMovie != movPtr->aMovie) || (result == TCL_BREAK)) { 4193 isHandled = true; 4194 4195 /* 4196 * We are still processing the old movie, and therefore need to stop any updates of it. 4197 * Seems not to work, schedule redisplay of new. 4198 */ 4199 4200 if (movPtr->tmpMovieRecordPtr != NULL) { 4201 MCGetControllerBoundsRect( movPtr->tmpMovieRecordPtr->movieController, &aRect ); 4202#if TARGET_API_MAC_CARBON 4203 { 4204 GWorldPtr destPort = NULL; 4205 4206 GetMovieGWorld( movPtr->tmpMovieRecordPtr->movie, &destPort, NULL ); 4207 //ValidWindowRect( GetWindowFromPort(destPort), &aRect ); 4208 } 4209#else 4210 ValidRect( &aRect ); 4211#endif 4212 } 4213 if (!(movPtr->flags & MOVIE_DELETED) && !(movPtr->flags & REDRAW_PENDING)) { 4214 Tcl_DoWhenIdle( DisplayMovie, (ClientData) movPtr ); 4215 movPtr->flags |= REDRAW_PENDING; 4216 } 4217 4218 QTTclDebugPrintf( interp, 2, 4219 "\tMovieControllerCallbackFunction:: isHandled = true" ); 4220 } 4221 4222bail: 4223 QTTclDebugPrintf( movPtr->interp, 4, "\tMovieControllerCallbackFunction exit" ); 4224 Tcl_Release( (ClientData) movPtr ); 4225 4226 return isHandled; 4227} 4228 4229/* 4230 *---------------------------------------------------------------------- 4231 * 4232 * MyQTVRInterceptProc -- 4233 * 4234 * Used to monitor user action in a QTVR movie. 4235 * 4236 * Results: 4237 * boolean 4238 * 4239 * Side effects: 4240 * the intercepted QTVR procedure called. 4241 * 4242 *---------------------------------------------------------------------- 4243 */ 4244 4245pascal void 4246MyQTVRInterceptProc( QTVRInstance qtvrInst, 4247 QTVRInterceptPtr msg, 4248 SInt32 refCon, 4249 Boolean *cancel ) 4250{ 4251 MoviePlayer *movPtr = (MoviePlayer *) refCon; 4252 Boolean hasCancelled = false; 4253 CGrafPtr saveWorld = NULL; 4254 GDHandle saveDevice = NULL; 4255 GWorldPtr destPort = NULL; 4256 Movie saveMovie = NULL; 4257 Rect aRect; 4258 int result = TCL_OK; 4259 char cmd[255]; 4260 char strPara[255]; 4261 float fValue; 4262 UInt32 uint32Value; 4263 OSType typeValue; 4264 4265 *cancel = hasCancelled; 4266 if (movPtr->mcCallbackProc == NULL) { 4267 return; 4268 } 4269 4270 /* 4271 * Signals that we does not exist anymore. 4272 */ 4273 4274 if (movPtr->flags & MOVIE_DELETED) { 4275 return; 4276 } 4277 4278 /* 4279 * We shall not call the tcl proc recursively since this screws up any idle calls 4280 * on exiting this function. 4281 */ 4282 4283 if (movPtr->insideMCCommand) { 4284 return; 4285 } 4286 Tcl_Preserve((ClientData) movPtr); 4287 4288 saveMovie = movPtr->aMovie; 4289 strcpy( cmd, movPtr->mcCallbackProc ); 4290 strcat( cmd, " " ); 4291 strcat( cmd, Tcl_GetCommandName(movPtr->interp, movPtr->widgetCmd) ); 4292 4293 switch (msg->selector) { 4294 case kQTVRSetPanAngleSelector: 4295 fValue = *((float *) msg->parameter[0]); 4296 strcat(cmd, " pan"); 4297 sprintf( strPara, " %f", RadiansToDegrees( fValue ) ); 4298 strcat( cmd, strPara ); 4299 break; 4300 case kQTVRSetTiltAngleSelector: 4301 fValue = *((float *) msg->parameter[0]); 4302 strcat(cmd, " tilt"); 4303 sprintf( strPara, " %f", RadiansToDegrees( fValue ) ); 4304 strcat( cmd, strPara ); 4305 break; 4306 case kQTVRSetFieldOfViewSelector: 4307 fValue = *((float *) msg->parameter[0]); 4308 strcat(cmd, " fieldofview"); 4309 sprintf( strPara, " %f", RadiansToDegrees( fValue ) ); 4310 strcat( cmd, strPara ); 4311 break; 4312 case kQTVRSetViewCenterSelector: 4313 4314 break; 4315 case kQTVRMouseEnterSelector: 4316 4317 break; 4318 case kQTVRMouseWithinSelector: 4319 4320 break; 4321 case kQTVRMouseLeaveSelector: 4322 4323 break; 4324 case kQTVRMouseDownSelector: 4325 /* 4326 strcat(cmd, " mouseDown"); 4327 sprintf( strPara, " {%f %f %d %d %d}", *((float *) msg->parameter[0]), 4328 *((float *) msg->parameter[1]), ((UInt32) msg->parameter[2]), 4329 ((UInt32) msg->parameter[3]), ((UInt32) msg->parameter[4]) ); 4330 strcat(cmd, strPara); */ 4331 break; 4332 case kQTVRMouseStillDownSelector: 4333 4334 break; 4335 case kQTVRMouseUpSelector: 4336 4337 break; 4338 case kQTVRTriggerHotSpotSelector: 4339 uint32Value = ((UInt32) msg->parameter[0]); 4340 strcat(cmd, " triggerhotspot"); 4341 sprintf( strPara, " %li", uint32Value ); 4342 strcat( cmd, strPara ); 4343 break; 4344 case kQTVRGetHotSpotTypeSelector: 4345 uint32Value = ((UInt32) msg->parameter[0]); 4346 typeValue = *((OSType *) msg->parameter[1]); 4347 strcat(cmd, " hotspottype"); 4348 sprintf( strPara, " %li %li", uint32Value, typeValue ); 4349 strcat( cmd, strPara ); 4350 4351 break; 4352 default: 4353 goto exit; 4354 } 4355 4356 movPtr->insideMCCommand++; 4357 result = Tcl_Eval( movPtr->interp, cmd ); 4358 movPtr->insideMCCommand--; 4359 4360 /* 4361 * Any 'update' command in the tcl procedure 4362 * ruins update events sent to redraw the controller, and we must therefore 4363 * invalidate, make dirty, the controller rectangle! 4364 * Beware, we may have been destroyed in the callback! Note Preserve/Release. 4365 */ 4366 4367 if (!(movPtr->flags & MOVIE_DELETED) && (movPtr->aController != NULL)) { 4368 GetGWorld( &saveWorld, &saveDevice ); 4369 GetMovieGWorld( movPtr->aMovie, &destPort, NULL ); 4370 SetGWorld( destPort, NULL ); 4371 MCGetControllerBoundsRect( movPtr->aController, &aRect ); 4372 aRect.top = aRect.bottom - movPtr->controllerHeight; 4373#if TARGET_API_MAC_CARBON 4374 InvalWindowRect( GetWindowFromPort(destPort), &aRect ); 4375#else 4376 InvalRect( &aRect ); 4377#endif 4378 SetGWorld( saveWorld, saveDevice ); 4379 } 4380 4381 /* 4382 * If the original movie was destroyed or configure -file, then we put the 4383 * destruction as an idle call so that we don't crash. 4384 */ 4385 4386 if (movPtr->tmpMovieRecordPtr) { 4387 Tcl_DoWhenIdle( DisposeMovieAtIdle, (ClientData) movPtr ); 4388 } 4389 4390 /* 4391 * We should return false to indicate that we only monitor the events here, 4392 * except if the callback script changed our movie (with configure -file), 4393 * or if script returned TCL_BREAK (break). 4394 */ 4395 4396 if ((saveMovie != movPtr->aMovie) || (result == TCL_BREAK)) { 4397 hasCancelled = true; 4398 4399 /* 4400 * We are still processing the old movie, and therefore need to stop any updates of it. 4401 * Seems not to work, schedule redisplay of new. 4402 */ 4403 4404 if (movPtr->tmpMovieRecordPtr) { 4405 MCGetControllerBoundsRect( movPtr->tmpMovieRecordPtr->movieController, &aRect ); 4406#if TARGET_API_MAC_CARBON 4407 GetMovieGWorld( movPtr->tmpMovieRecordPtr->movie, &destPort, NULL ); 4408 ValidWindowRect( GetWindowFromPort(destPort), &aRect ); 4409#else 4410 ValidRect( &aRect ); 4411#endif 4412 } 4413 if (!(movPtr->flags & MOVIE_DELETED) && !(movPtr->flags & REDRAW_PENDING)) { 4414 Tcl_DoWhenIdle( DisplayMovie, (ClientData) movPtr ); 4415 movPtr->flags |= REDRAW_PENDING; 4416 } 4417 4418 QTTclDebugPrintf( movPtr->interp, 2, "\tsaveMovie=%d, movPtr->aMovie=%d", 4419 saveMovie, movPtr->aMovie ); 4420 } 4421 4422exit: 4423 Tcl_Release((ClientData) movPtr); 4424 *cancel = hasCancelled; 4425} 4426 4427/* 4428 *---------------------------------------------------------------------- 4429 * 4430 * ControllerCallbackTimer -- 4431 * 4432 * Timer function for tcl callbacks from the controller. 4433 * (Presently unused; does not fix update problem!) 4434 * 4435 * Results: 4436 * None. 4437 * 4438 * Side effects: 4439 * 4440 * 4441 *---------------------------------------------------------------------- 4442 */ 4443 4444static void 4445ControllerCallbackTimer ( ClientData clientData ) 4446{ 4447 int result; 4448 ControllerTimerRecord *timerPtr = (ControllerTimerRecord *) clientData; 4449 4450 /* 4451 * Perform the actual call to the registered tcl procedure. 4452 */ 4453 4454 result = Tcl_Eval( timerPtr->movPtr->interp, timerPtr->tclCmd ); 4455 4456 /* Release memory! */ 4457 ckfree( timerPtr->tclCmd ); 4458 ckfree( (char *) timerPtr ); 4459} 4460 4461/* 4462 *---------------------------------------------------------------------- 4463 * 4464 * LogUndoState -- 4465 * 4466 * Capture an UnDo state. 4467 * 4468 * Results: 4469 * Normal TCL results 4470 * 4471 * Side effects: 4472 * Remembers where we are in a movie, memory is likely allocated. 4473 * Result in interpreter as a list '-undostate number'. 4474 * 4475 *---------------------------------------------------------------------- 4476 */ 4477 4478int 4479LogUndoState( MoviePlayer *movPtr, Tcl_Interp *interp) 4480{ 4481 MovieEditState *tmparr = NULL; 4482 int result = TCL_OK; 4483 int i; 4484 Tcl_Obj *listObjPtr; 4485 4486 /* Do we need to make the array bigger? */ 4487 4488 if (movPtr->undoCount >= movPtr->editStatesSize) { 4489 tmparr = (MovieEditState *) 4490 ckalloc( sizeof(MovieEditState)*(UNDO_SIZE + movPtr->editStatesSize) ); 4491 if (tmparr == NULL) { 4492 Tcl_SetObjResult( interp, Tcl_NewStringObj( "Out of Memory", -1 ) ); 4493 return TCL_ERROR; 4494 } 4495 if (movPtr->editStates) { 4496 for (i = 0; i < movPtr->editStatesSize; i++) { 4497 tmparr[i] = movPtr->editStates[i]; 4498 } 4499 ckfree((char *) movPtr->editStates); 4500 } 4501 movPtr->editStates = tmparr; 4502 movPtr->editStatesSize += UNDO_SIZE; 4503 } 4504 4505 movPtr->editStates[movPtr->undoCount] = NewMovieEditState( movPtr->aMovie ); 4506 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 4507 Tcl_ListObjAppendElement( interp, listObjPtr, 4508 Tcl_NewStringObj("-undostate", -1) ); 4509 Tcl_ListObjAppendElement( interp, listObjPtr, 4510 Tcl_NewIntObj(movPtr->undoCount) ); 4511 Tcl_AppendObjToObj( Tcl_GetObjResult( interp ), listObjPtr ); 4512 movPtr->undoCount++; 4513 4514 return result; 4515} 4516 4517/* 4518 *---------------------------------------------------------------------- 4519 * 4520 * AddImagesToMovie -- 4521 * 4522 * Add images to a media with a duration of duration. 4523 * 4524 * Results: 4525 * Normal Tcl 4526 * 4527 * Side effects: 4528 * Memory allocated, any error messages in the interpreter. 4529 * 4530 *---------------------------------------------------------------------- 4531 */ 4532 4533int 4534AddImagesToMovie( Tcl_Interp *interp, 4535 Media myMedia, /* the media (in) */ 4536 TimeValue durationPerFrame, /* the duration of one frame in media's time scale (in) */ 4537 int nPhotos, /* number of photos in array (in) */ 4538 Tk_PhotoHandle *photoList, /* the photo (in) */ 4539 int showDialog, /* show dialog ? (in) */ 4540 CodecType codecType, /* the compressor type to use (in) */ 4541 CodecQ spatialQuality, 4542 CodecQ temporalQuality, 4543 short colorDepth, 4544 long keyFrameRate, 4545 TimeValue *sampleTimePtr ) /* returns the position where the first sample was inserted 4546 * in the media, in media's time (out) */ 4547{ 4548 GWorldPtr theGWorld = NULL; 4549 CGrafPtr oldPort = NULL; 4550 GDHandle oldGDeviceH = NULL; 4551 ImageDescriptionHandle imageDesc = NULL; 4552 ImageSequence sequenceID = 0; 4553 ComponentInstance ci = NULL; 4554 ComponentResult err = noErr; 4555 OSErr osErr = noErr; 4556 long maxCompressedSize; 4557 long dataSize; 4558 Handle compressedData = NULL; 4559 Ptr compressedDataPtr = NULL; 4560 Ptr nextDataPtr = NULL; 4561 TimeValue thisSampleTime; 4562 short syncFlag = 0; 4563 PixMapHandle pixels = NULL; 4564 int pixelDepth; 4565 Tk_PhotoImageBlock photoBlock; 4566 unsigned char *pixelPtr; 4567 unsigned char *photoPixels; 4568 Rect myRect; 4569 Tcl_Obj *resultObjPtr; 4570 int right, bottom; 4571 int iphoto; 4572 int nPhotosInBatch; 4573 int i, j; 4574 int result = TCL_OK; 4575 int useStandardCompress = true; /* mainly for testing */ 4576 4577 if (nPhotos <= 0) { 4578 return TCL_ERROR; 4579 } 4580 if ((nPhotos > 1) || showDialog) { 4581 useStandardCompress = true; 4582 } 4583 4584 GetGWorld( &oldPort, &oldGDeviceH ); 4585 Tk_PhotoGetSize( photoList[0], &right, &bottom ); 4586 myRect.top = 0; 4587 myRect.left = 0; 4588 myRect.right = right; 4589 myRect.bottom = bottom; 4590 err = QTNewGWorld( &theGWorld, 32, &myRect, NULL, NULL, kICMTempThenAppMemory ); 4591 if (err != noErr) { 4592 CheckAndSetErrorResult( interp, err ); 4593 result = TCL_ERROR; 4594 goto done; 4595 } 4596 4597 SetGWorld( theGWorld, NULL ); 4598 pixels = GetGWorldPixMap( theGWorld ); 4599 4600 /* 4601 * Lock down the pixels so they don't move out from under us. 4602 */ 4603 4604 LockPixels(pixels); 4605 4606 /* 4607 * If we are using CompressImage and has a specific colorDepth, it is necessary 4608 * to make a GWorld of that colorDepth. 4609 */ 4610 4611 if (!showDialog && ((colorDepth != 0) && (colorDepth != 32))) { 4612 int ans; 4613 4614 if (colorDepth <= 32) { 4615 pixelDepth = colorDepth; 4616 } else { 4617 pixelDepth = colorDepth - 32; 4618 } 4619 ans = DoesCodecSupport( codecType, kDoesCodecPixmapDepth, pixelDepth ); 4620 if (ans == false) { 4621 Tcl_SetObjResult( interp, Tcl_NewStringObj( 4622 "Compressor does not support this colordepth", -1 ) ); 4623 result = TCL_ERROR; 4624 goto done; 4625 } 4626 ans = DoesCodecSupport( codecType, kDoesCodecCompressDepth, colorDepth ); 4627 if (ans == false) { 4628 Tcl_SetObjResult( interp, Tcl_NewStringObj( 4629 "Compressor does not support this colordepth", -1 ) ); 4630 result = TCL_ERROR; 4631 goto done; 4632 } 4633 } 4634 4635 imageDesc = (ImageDescriptionHandle) NewHandle(4); 4636 4637 if (!useStandardCompress && !showDialog && (nPhotos > 1)) { 4638 4639 /* 4640 * Initialize the dialogless sequence compressor. 4641 */ 4642 4643 err = CompressSequenceBegin( 4644 &sequenceID, /* unique identifier for this sequence */ 4645 pixels, 4646 NULL, /* tell ICM to allocate previous buffer */ 4647 &myRect, 4648 &myRect, 4649 colorDepth, 4650 codecType, 4651 (CompressorComponent) anyCodec, 4652 spatialQuality, /* spatial quality */ 4653 temporalQuality, /* temporal quality */ 4654 keyFrameRate, /* key frame rate */ 4655 NULL, /* default color table */ 4656 codecFlagUpdatePrevious, 4657 imageDesc ); 4658 if (err != noErr) { 4659 UnlockPixels(pixels); 4660 CheckAndSetErrorResult( interp, err ); 4661 result = TCL_ERROR; 4662 goto done; 4663 } 4664 nPhotosInBatch = nPhotos; 4665 } else { 4666 nPhotosInBatch = 1; 4667 } 4668 if (!useStandardCompress) { 4669 err = GetMaxCompressionSize( pixels, 4670 &myRect, 4671 colorDepth, 4672 spatialQuality, 4673 codecType, 4674 (CompressorComponent) anyCodec, 4675 &maxCompressedSize ); 4676 maxCompressedSize *= nPhotosInBatch; 4677 if (err != noErr) { 4678 UnlockPixels( pixels ); 4679 CheckAndSetErrorResult( interp, err ); 4680 result = TCL_ERROR; 4681 goto done; 4682 } 4683 compressedData = MySafeNewHandle( maxCompressedSize, 0 ); 4684 if (osErr != noErr) { 4685 panic( "Out of memory in AddImagesToMovie" ); 4686 } 4687 4688 MoveHHi( compressedData ); 4689 HLock( compressedData ); 4690#if TARGET_API_MAC_CARBON 4691 compressedDataPtr = *compressedData; 4692#else 4693 compressedDataPtr = StripAddress( *compressedData ); 4694#endif 4695 nextDataPtr = compressedDataPtr; 4696 } 4697 if (useStandardCompress) { 4698 err = OpenADefaultComponent( StandardCompressionType, 4699 StandardCompressionSubType, &ci ); 4700 if (err != noErr) { 4701 result = TCL_ERROR; 4702 CheckAndSetErrorResult( interp, err ); 4703 goto done; 4704 } 4705 4706 /* 4707 * If setting defaults of the compressor cmponent like this, we 4708 * can avoid having the dialog displayed. 4709 * Thanks to Kevin Marks at Apple for this one. 4710 */ 4711 4712 if (!showDialog) { /* not sure about this... */ 4713 SCSpatialSettings spatSet; 4714 SCTemporalSettings tempSet; 4715 SCDataRateSettings rateSet; 4716 4717 SCGetInfo( ci, scSpatialSettingsType, &spatSet ); 4718 SCGetInfo( ci, scTemporalSettingsType, &tempSet ); 4719 SCGetInfo( ci, scDataRateSettingsType, &rateSet ); 4720 4721 spatSet.codecType = codecType; 4722 spatSet.codec = anyCodec; 4723 spatSet.depth = colorDepth; 4724 spatSet.spatialQuality = spatialQuality; 4725 tempSet.temporalQuality = temporalQuality; 4726 tempSet.keyFrameRate = keyFrameRate; 4727 rateSet.minSpatialQuality = spatialQuality; 4728 rateSet.minTemporalQuality = temporalQuality; 4729 4730 SCSetInfo( ci, scSpatialSettingsType, &spatSet ); 4731 SCSetInfo( ci, scTemporalSettingsType, &tempSet ); 4732 SCSetInfo( ci, scDataRateSettingsType, &rateSet ); 4733 } 4734 } 4735 4736 /* 4737 * Loop over all photos we have got. 4738 */ 4739 4740 for (iphoto = 0; iphoto < nPhotos; iphoto++) { 4741 4742 Tk_PhotoGetSize( photoList[iphoto], &right, &bottom ); 4743 if ((right != myRect.right) && (bottom != myRect.bottom)) { 4744 resultObjPtr = Tcl_GetObjResult( interp ); 4745 Tcl_AppendObjToObj( resultObjPtr, 4746 Tcl_NewStringObj( "image number ", -1 ) ); 4747 Tcl_AppendObjToObj( resultObjPtr, Tcl_NewIntObj( iphoto + 1 ) ); 4748 Tcl_AppendObjToObj( resultObjPtr, 4749 Tcl_NewStringObj( " has a different size than previous", -1 ) ); 4750 Tcl_SetObjResult( interp, resultObjPtr ); 4751 result = TCL_ERROR; 4752 goto done; 4753 } 4754 Tk_PhotoGetImage( photoList[iphoto], &photoBlock ); 4755 4756 /* 4757 * Copy the pixels to the gworld. 4758 * The Mac pixmap stores them as "undefined, red, gree, blue", but tk 8.3 stores them 4759 * as "red, green, blue, alpha (transparency)". 4760 */ 4761 4762 for (i = 0; i < photoBlock.height; i++) { 4763 pixelPtr = (unsigned char *) 4764 (GetPixBaseAddr(pixels) + i * (0x3FFF & ((*pixels)->rowBytes))); 4765 photoPixels = photoBlock.pixelPtr + i * photoBlock.pitch; 4766 for (j =0; j < photoBlock.width; j++) { 4767#if TK_MINOR_VERSION <= 2 4768 *pixelPtr = 0; pixelPtr++; 4769#else 4770 *pixelPtr = *(photoPixels + photoBlock.offset[3]); pixelPtr++; 4771#endif 4772 *pixelPtr = *(photoPixels + photoBlock.offset[0]); pixelPtr++; 4773 *pixelPtr = *(photoPixels + photoBlock.offset[1]); pixelPtr++; 4774 *pixelPtr = *(photoPixels + photoBlock.offset[2]); pixelPtr++; 4775 photoPixels += photoBlock.pixelSize; 4776 } 4777 } 4778 4779 /* 4780 * There are four possibilities here: with or without dialog, 4781 * and single image or sequence of images. 4782 */ 4783 4784 if (useStandardCompress || showDialog) { 4785 if (nPhotos == 1) { 4786 if (showDialog) { 4787 SCSetTestImagePixMap( ci, pixels, NULL, scPreferCropping ); 4788 InstallExtendedSCCallbackProcedures( ci, (long) interp ); 4789 SCDefaultPixMapSettings( ci, pixels, false ); 4790 err = SCRequestImageSettings( ci ); 4791 if (err == scUserCancelled) { 4792 4793 /* Perhaps we should return something here and set the error code */ 4794 goto done; 4795 } else if (err != noErr) { 4796 result = TCL_ERROR; 4797 CheckAndSetErrorResult( interp, err ); 4798 goto done; 4799 } 4800 } 4801 err = SCCompressImage( ci, 4802 pixels, 4803 &myRect, 4804 &imageDesc, 4805 &compressedData ); 4806 } else { 4807 4808 /* 4809 * Sequence. 4810 */ 4811 4812 if (iphoto == 0) { 4813 if (showDialog) { 4814 SCSetTestImagePixMap( ci, pixels, NULL, scPreferCropping ); 4815 InstallExtendedSCCallbackProcedures( ci, (long) interp ); 4816 SCDefaultPixMapSettings( ci, pixels, true ); 4817 err = SCRequestSequenceSettings( ci ); 4818 if (err == scUserCancelled) { 4819 4820 /* Perhaps we should return something here and set the error code */ 4821 goto done; 4822 } else if (err != noErr) { 4823 result = TCL_ERROR; 4824 CheckAndSetErrorResult( interp, err ); 4825 goto done; 4826 } 4827 } 4828 err = SCCompressSequenceBegin( ci, pixels, &myRect, &imageDesc ); 4829 if (err != noErr) { 4830 result = TCL_ERROR; 4831 CheckAndSetErrorResult( interp, err ); 4832 goto done; 4833 } 4834 } 4835 err = SCCompressSequenceFrame( ci, pixels, &myRect, 4836 &compressedData, 4837 &dataSize, 4838 &syncFlag ); 4839 (**imageDesc).dataSize = dataSize; 4840 } 4841 } else { /* dialogless, old compress */ 4842 4843 if (nPhotos == 1) { 4844 err = CompressImage( pixels, 4845 &myRect, 4846 spatialQuality, 4847 codecType, 4848 imageDesc, 4849 compressedDataPtr ); 4850 } else { 4851 err = CompressSequenceFrame( sequenceID, 4852 pixels, 4853 &myRect, 4854 codecFlagUpdatePrevious, 4855 nextDataPtr, 4856 &dataSize, 4857 NULL, 4858 NULL ); 4859 nextDataPtr += dataSize; 4860 } 4861 } 4862 if (err != noErr) { 4863 result = TCL_ERROR; 4864 CheckAndSetErrorResult( interp, err ); 4865 goto done; 4866 } 4867 if ((nPhotosInBatch == 1) || (iphoto = nPhotosInBatch - 1)) { 4868 err = AddMediaSample( myMedia, 4869 compressedData, 4870 0, /* no offset in data */ 4871 (**imageDesc).dataSize, 4872 durationPerFrame, /* frame duration */ 4873 (SampleDescriptionHandle) imageDesc, 4874 nPhotosInBatch, /* one sample or the complete sequence */ 4875 syncFlag, /* key frame or not */ 4876 &thisSampleTime ); 4877 } 4878 4879 /* 4880 * Important that we return the media position where the first frame was stored! 4881 */ 4882 4883 if (iphoto == 0) { 4884 *sampleTimePtr = thisSampleTime; 4885 } 4886 if (err != noErr) { 4887 result = TCL_ERROR; 4888 CheckAndSetErrorResult( interp, err ); 4889 goto done; 4890 } 4891 } /* end loop over photos */ 4892 4893done: 4894 4895 UnlockPixels(pixels); 4896 SetGWorld(oldPort, oldGDeviceH); 4897 if (nPhotos > 1) { 4898 if (useStandardCompress || showDialog) { 4899 4900 /* disposes imageDesc and compressedData handles */ 4901 SCCompressSequenceEnd(ci); 4902 } else { 4903 CDSequenceEnd(sequenceID); 4904 } 4905 } 4906 if (imageDesc) { 4907 DisposeHandle((Handle) imageDesc); 4908 } 4909 if (compressedData) { 4910 DisposeHandle(compressedData); 4911 } 4912 if (ci) { 4913 CloseComponent(ci); 4914 } 4915 if (theGWorld) { 4916 DisposeGWorld(theGWorld); 4917 } 4918 return result; 4919} 4920 4921/* 4922 *---------------------------------------------------------------------- 4923 * 4924 * AddImageFileToMovie -- 4925 * 4926 * Add images to a media with a duration of duration. 4927 * 4928 * Results: 4929 * Normal Tcl 4930 * 4931 * Side effects: 4932 * Memory allocated, any error messages in the interpreter. 4933 * 4934 *---------------------------------------------------------------------- 4935 */ 4936 4937int 4938AddImageFileToMovie( Tcl_Interp *interp, 4939 Media myMedia, /* the media (in) */ 4940 TimeValue duration, /* the duration of one frame in media's time scale (in) */ 4941 char *fileName, /* file name (in) */ 4942 long optFlags, /* flags specifying options set (in) */ 4943 int showDialog, /* show dialog ? (in) */ 4944 CodecType codecType, /* the compressor type to use (in) */ 4945 CodecQ spatialQuality, 4946 CodecQ temporalQuality, 4947 short colorDepth, 4948 long keyFrameRate, 4949 TimeValue *sampleTimePtr ) /* returns the position where the first sample was inserted 4950 * in the media, in media's time (out) */ 4951{ 4952 GWorldPtr theGWorld = NULL; 4953 PixMapHandle pixels = NULL; 4954 ComponentResult err = noErr; 4955 ComponentInstance gi = NULL; 4956 ComponentInstance ci = NULL; 4957 ImageDescriptionHandle srcImageDesc = NULL; 4958 ImageDescriptionHandle dstImageDesc = NULL; 4959 Handle compressedData = NULL; 4960 Rect bounds; 4961 SCSpatialSettings spatSet; 4962 SCTemporalSettings tempSet; 4963 SCDataRateSettings rateSet; 4964 FSSpec fss; 4965 CTabHandle colTabHandle = NULL; 4966 short pixelDepth; 4967 int result = TCL_OK; 4968 4969 err = QTTclNativePathNameToFSSpec( interp, fileName, &fss ); 4970 if (err != noErr) { 4971 Tcl_SetObjResult( interp, Tcl_NewStringObj( 4972 "Failed making FSSpec from filename", -1 ) ); 4973 result = TCL_ERROR; 4974 goto done; 4975 } 4976 4977 /* This can be slow :-( */ 4978 err = GetGraphicsImporterForFile( &fss, &gi ); 4979 if (err != noErr) { 4980 result = TCL_ERROR; 4981 CheckAndSetErrorResult( interp, err ); 4982 goto done; 4983 } 4984 err = GraphicsImportGetImageDescription( gi, &srcImageDesc ); 4985 if (err != noErr) { 4986 result = TCL_ERROR; 4987 CheckAndSetErrorResult( interp, err ); 4988 goto done; 4989 } 4990 err = GraphicsImportGetNaturalBounds( gi, &bounds ); 4991 if (err != noErr) { 4992 result = TCL_ERROR; 4993 CheckAndSetErrorResult( interp, err ); 4994 goto done; 4995 } 4996 4997 /* 4998 * Try to be as faithful as possible to the original image. Depth and color table. 4999 */ 5000 5001 if ((**srcImageDesc).depth > 32) { 5002 pixelDepth = (**srcImageDesc).depth - 32; 5003 } else { 5004 pixelDepth = (**srcImageDesc).depth; 5005 } 5006 if ((**srcImageDesc).clutID == 0) { 5007 err = GetImageDescriptionCTable( srcImageDesc, &colTabHandle ); 5008 if (err != noErr) { 5009 result = TCL_ERROR; 5010 CheckAndSetErrorResult( interp, err ); 5011 goto done; 5012 } 5013 if (((**colTabHandle).ctSize == 0) || ((**colTabHandle).ctSeed < 0)) { 5014 if (colTabHandle) { 5015 DisposeCTable(colTabHandle); 5016 } 5017 colTabHandle = NULL; 5018 } 5019 } 5020 err = QTNewGWorld( &theGWorld, pixelDepth, &bounds, colTabHandle, NULL, 5021 kICMTempThenAppMemory ); 5022 if (err != noErr) { 5023 CheckAndSetErrorResult( interp, err ); 5024 result = TCL_ERROR; 5025 goto done; 5026 } 5027 GraphicsImportSetGWorld( gi, theGWorld, NULL ); 5028 err = GraphicsImportDraw( gi ); 5029 if (err != noErr) { 5030 CheckAndSetErrorResult( interp, err ); 5031 result = TCL_ERROR; 5032 goto done; 5033 } 5034 5035 /* 5036 * Time to compress the thing. Set defaults from pixmap and image description. 5037 */ 5038 5039 err = OpenADefaultComponent( StandardCompressionType, StandardCompressionSubType, &ci ); 5040 if (err != noErr) { 5041 CheckAndSetErrorResult( interp, err ); 5042 result = TCL_ERROR; 5043 goto done; 5044 } 5045 pixels = GetGWorldPixMap( theGWorld ); 5046 LockPixels( pixels ); 5047 SCDefaultPixMapSettings( ci, pixels, false ); 5048 5049 SCGetInfo( ci, scSpatialSettingsType, &spatSet ); 5050 SCGetInfo( ci, scTemporalSettingsType, &tempSet ); 5051 SCGetInfo( ci, scDataRateSettingsType, &rateSet ); 5052 5053 spatSet.codecType = (**srcImageDesc).cType; 5054 spatSet.spatialQuality = (**srcImageDesc).spatialQuality; 5055 5056 /* 5057 * Override options from file with any command line options. 5058 */ 5059 5060 if (optFlags & kCompressFlagColorDepth) { 5061 spatSet.depth = colorDepth; 5062 } 5063 if (optFlags & kCompressFlagCompressor) { 5064 spatSet.codecType = codecType; 5065 } 5066 if (optFlags & kCompressFlagKeyFrameRate) { 5067 tempSet.keyFrameRate = keyFrameRate; 5068 } 5069 if (optFlags & kCompressFlagSpatialQuality) { 5070 spatSet.spatialQuality = spatialQuality; 5071 } 5072 if (optFlags & kCompressFlagTemporalQuality) { 5073 tempSet.temporalQuality = temporalQuality; 5074 } 5075 SCSetInfo( ci, scSpatialSettingsType, &spatSet ); 5076 SCSetInfo( ci, scTemporalSettingsType, &tempSet ); 5077 SCSetInfo( ci, scDataRateSettingsType, &rateSet ); 5078 5079 if (showDialog) { 5080 SCSetTestImagePixMap( ci, pixels, NULL, scPreferCropping ); 5081 InstallExtendedSCCallbackProcedures( ci, (long) interp ); 5082 SCDefaultPixMapSettings( ci, pixels, true ); 5083 err = SCRequestSequenceSettings( ci ); 5084 if (err == scUserCancelled) { 5085 5086 /* Perhaps we should return something here and set the error code??? */ 5087 goto done; 5088 } else if (err != noErr) { 5089 result = TCL_ERROR; 5090 CheckAndSetErrorResult( interp, err ); 5091 goto done; 5092 } 5093 } 5094 err = SCCompressImage( ci, 5095 pixels, 5096 &bounds, 5097 &dstImageDesc, 5098 &compressedData ); 5099 if (err != noErr) { 5100 result = TCL_ERROR; 5101 CheckAndSetErrorResult( interp, err ); 5102 goto done; 5103 } 5104 err = AddMediaSample( myMedia, 5105 compressedData, 5106 0, /* no offset in data */ 5107 (**dstImageDesc).dataSize, 5108 duration, /* frame duration */ 5109 (SampleDescriptionHandle) dstImageDesc, 5110 1, /* one sample or the complete sequence */ 5111 0, /* key frame or not */ 5112 sampleTimePtr ); 5113 if (err != noErr) { 5114 result = TCL_ERROR; 5115 CheckAndSetErrorResult( interp, err ); 5116 goto done; 5117 } 5118 5119 5120done: 5121 5122 if (gi) { 5123 CloseComponent(gi); 5124 } 5125 if (ci) { 5126 CloseComponent(ci); 5127 } 5128 if (srcImageDesc) { 5129 DisposeHandle((Handle) srcImageDesc); 5130 } 5131 if (dstImageDesc) { 5132 DisposeHandle((Handle) dstImageDesc); 5133 } 5134 if (colTabHandle) { 5135 DisposeCTable(colTabHandle); 5136 } 5137 if (compressedData) { 5138 DisposeHandle(compressedData); 5139 } 5140 if (theGWorld) { 5141 DisposeGWorld(theGWorld); 5142 } 5143 return result; 5144} 5145 5146/* 5147 *---------------------------------------------------------------------- 5148 * 5149 * MoviePlayerEventProc -- 5150 * 5151 * Deal with Movie Events, these events are TCL events. 5152 * Update (Expose) events for a movie with controller are dealt 5153 * with in MCIsPlayerEvent in 'MoviePlayerMacEvent'. 5154 * 5155 * Results: 5156 * None. 5157 * 5158 * Side effects: 5159 * Depends on event. 5160 * 5161 *---------------------------------------------------------------------- 5162 */ 5163 5164static void 5165MoviePlayerEventProc(ClientData clientData, XEvent *eventPtr) 5166{ 5167 MoviePlayer *movPtr = (MoviePlayer *) clientData; 5168 5169 QTTclDebugPrintf( movPtr->interp, 2, 5170 "MoviePlayerEventProc: type=%d, flags=%1d%1d%1d%1d%1d%1d", 5171 eventPtr->type, (movPtr->flags >> 5) & 0x1, (movPtr->flags >> 4) & 0x1, 5172 (movPtr->flags >> 3) & 0x1, (movPtr->flags >> 2) & 0x1, 5173 (movPtr->flags >> 1) & 0x1, (movPtr->flags >> 0) & 0x1 ); 5174 5175 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { 5176 movPtr->flags |= UPDATEMOVIE; 5177 goto redraw; 5178 } else if (eventPtr->type == ConfigureNotify) { 5179 goto redraw; 5180 } else if (eventPtr->type == MapNotify) { 5181 5182#if TARGET_API_MAC_CARBON 5183 /* 5184 * Is this the right place to install the Carbon window event handler? 5185 */ 5186 5187 InstallCarbonWindowEventHandler( movPtr ); 5188#endif 5189 movPtr->flags |= NEWGWORLD; 5190 goto redraw; 5191 } else if (eventPtr->type == UnmapNotify) { 5192 5193 /* 5194 * We do not want to serve it anymore; if async loaded it still gets served, 5195 * but what about the GWorld? 5196 */ 5197 5198 movPtr->state &= ~kQTTclMovieStateOnDisplay; 5199 movPtr->grafPtr = NULL; 5200 return; 5201 } else if (eventPtr->type == FocusIn) { 5202 movPtr->flags |= GOT_FOCUS; 5203 goto redraw; 5204 } else if (eventPtr->type == FocusOut) { 5205 movPtr->flags &= ~GOT_FOCUS; 5206 goto redraw; 5207 } else if (eventPtr->type == DestroyNotify) { 5208 DestroyMovie( movPtr ); 5209 } 5210 return; 5211 5212redraw: 5213 5214 if (!(movPtr->flags & MOVIE_DELETED) && !(movPtr->flags & REDRAW_PENDING)) { 5215 Tcl_DoWhenIdle( DisplayMovie, (ClientData) movPtr ); 5216 movPtr->flags |= REDRAW_PENDING; 5217 } 5218} 5219 5220/* 5221 *---------------------------------------------------------------------- 5222 * 5223 * MoviePlayerDeletedProc -- 5224 * 5225 * Deletes a MoviePlayer widget. 5226 * 5227 * Results: 5228 * None. 5229 * 5230 * Side effects: 5231 * DestroyMovie implicitly called. 5232 * 5233 *---------------------------------------------------------------------- 5234 */ 5235 5236static void 5237MoviePlayerDeletedProc( ClientData clientData ) 5238{ 5239 MoviePlayer *movPtr = (MoviePlayer *) clientData; 5240 5241 /* 5242 * This procedure could be invoked either because the window was 5243 * destroyed and the command was then deleted or because the command 5244 * was deleted, and then this procedure destroys the widget. The 5245 * MOVIE_DELETED flag distinguishes these cases. 5246 */ 5247 5248 if (!(movPtr->flags & MOVIE_DELETED)) { 5249 Tk_DestroyWindow( movPtr->tkwin ); 5250 } 5251} 5252 5253/* 5254 *---------------------------------------------------------------------- 5255 * 5256 * DestroyMovie -- 5257 * 5258 * Deletes a MoviePlayer Widget. Most things cleaned up with 5259 * Tk_FreeOptions but some things are freed up by me. 5260 * 5261 * Results: 5262 * None. 5263 * 5264 * Side effects: 5265 * Schedules or calls directly MoviePlayerFree to free all resources. 5266 * 5267 *---------------------------------------------------------------------- 5268 */ 5269 5270static void 5271DestroyMovie( MoviePlayer *movPtr ) 5272{ 5273 QTTclDebugPrintf( movPtr->interp, 2, "DestroyMovie: movPtr=%d", movPtr ); 5274 movPtr->flags |= MOVIE_DELETED; 5275 5276#if TARGET_API_MAC_CARBON 5277 MovieDestroyCarbonWindowHandlerCleanup( movPtr ); 5278#endif 5279 5280 if (movPtr->flags & REDRAW_PENDING) { 5281 Tcl_CancelIdleCall( DisplayMovie, (ClientData) movPtr ); 5282 } 5283 Tcl_DeleteCommandFromToken( movPtr->interp, movPtr->widgetCmd ); 5284 5285 /* 5286 * Remove from the display list. 5287 */ 5288 5289 RemoveMovieFromOpenMovies( movPtr ); 5290 5291 /* 5292 * This is the "protected" free procedure. Anything Tcl_Preserve'ed 5293 * is not freed until Tcl_Release'ed. 5294 */ 5295 5296 Tcl_EventuallyFree( (ClientData) movPtr, MoviePlayerFree ); 5297} 5298 5299/* 5300 *---------------------------------------------------------------------- 5301 * 5302 * MoviePlayerFree -- 5303 * 5304 * Does the real job of freeing memory, Movie, and MovieController. 5305 * 5306 * Results: 5307 * None. 5308 * 5309 * Side effects: 5310 * Hopefully frees memory. 5311 * 5312 *---------------------------------------------------------------------- 5313 */ 5314 5315static void 5316MoviePlayerFree( char *clientData ) 5317{ 5318 MoviePlayer *movPtr = (MoviePlayer *) clientData; 5319 int i; 5320 5321 QTTclDebugPrintf( movPtr->interp, 2, "MoviePlayerFree: movPtr=%d", movPtr ); 5322 5323 if (movPtr->trackSelect != NULL) { 5324 ckfree( (char *) movPtr->trackSelect ); 5325 movPtr->trackSelect = NULL; 5326 } 5327 5328 /* Delete and free any async load async callbacks. */ 5329 AsyncLoadFree( movPtr ); 5330 5331 if (movPtr->aMovie != NULL) { 5332 for (i = 0; i < movPtr->undoCount; i++) { 5333 DisposeMovieEditState( movPtr->editStates[i] ); 5334 } 5335 movPtr->undoCount = 0; 5336 if (movPtr->editStates) { 5337 ckfree( (char *) movPtr->editStates ); 5338 } 5339 CallBackFree( movPtr ); 5340 5341 /* 5342 * If called from inside the -mccommand proc we destroy the actual movie at idle. 5343 */ 5344 5345 if (movPtr->insideMCCommand) { 5346 movPtr->tmpMovieRecordPtr = (TmpMovieRecord *) ckalloc( sizeof(TmpMovieRecord) ); 5347 movPtr->tmpMovieRecordPtr->movie = movPtr->aMovie; 5348 movPtr->tmpMovieRecordPtr->movieController = movPtr->aController; 5349 SetMovieGWorld( movPtr->aMovie, gOffscreenGWorldPtr, NULL ); 5350 movPtr->aMovie = NULL; 5351 movPtr->aController = NULL; 5352 } else { 5353 if (movPtr->aController != NULL) { 5354 DisposeMovieController( movPtr->aController ); 5355 movPtr->aController = NULL; 5356 } 5357 if (movPtr->aMovie != NULL) { 5358 QTTclDebugPrintf( movPtr->interp, 2, "\taMovie=%d", movPtr->aMovie ); 5359 DisposeMovie( movPtr->aMovie ); 5360 movPtr->aMovie = NULL; 5361 gMovieRefCount--; 5362 } 5363 } 5364 } 5365 5366#ifdef _WIN32 5367 if (movPtr->hwnd != NULL) { 5368 /* There have been a previous crash problem from DestroyPortAssociation 5369 * but that was likely due to ExitMovies could be called before this. */ 5370 /* IMPORTANT: Must be after movie is disposed!!! */ 5371 DestroyPortAssociation( (CGrafPtr) GetHWNDPort(movPtr->hwnd) ); 5372 movPtr->hwnd = NULL; 5373 } 5374#endif 5375 5376 Tk_FreeConfigOptions( (char *) movPtr, movPtr->optionTable, movPtr->tkwin ); 5377 ckfree( (char *) movPtr ); 5378 5379 /* 5380 * If this is the last movie destroyed and the exit handler 5381 * has been called and not yet freed it must be done now. 5382 */ 5383 if ((gExitState == kQTTclExitStateExitHandlerCalled) && (gMovieRefCount <= 0)) { 5384 ExitMoviePlayer( NULL ); 5385 } 5386} 5387 5388/* 5389 *---------------------------------------------------------------------- 5390 * 5391 * DisposeMovieAtIdle -- 5392 * 5393 * When doing 'configure -file' from the '-mccommand' tcl proc it 5394 * crashes for QTVR movies if not disposing movie at idle. 5395 * 5396 * Results: 5397 * None. 5398 * 5399 * Side effects: 5400 * Movie and controller disposed. 5401 * 5402 *---------------------------------------------------------------------- 5403 */ 5404 5405static void 5406DisposeMovieAtIdle( ClientData clientData ) 5407{ 5408 MoviePlayer *movPtr = (MoviePlayer *) clientData; 5409 5410 QTTclDebugPrintf( movPtr->interp, 2, "DisposeMovieAtIdle" ); 5411 5412 if (gExitState > 0) { 5413 return; 5414 } 5415 if (movPtr->tmpMovieRecordPtr == NULL) { 5416 return; 5417 } 5418 if (movPtr->tmpMovieRecordPtr->movieController != NULL) { 5419 DisposeMovieController( movPtr->tmpMovieRecordPtr->movieController ); 5420 } 5421 if (movPtr->tmpMovieRecordPtr->movie != NULL) { 5422 QTTclDebugPrintf( movPtr->interp, 2, "\tmovPtr->tmpMovieRecordPtr->movie=%d", 5423 movPtr->tmpMovieRecordPtr->movie ); 5424 DisposeMovie( movPtr->tmpMovieRecordPtr->movie ); 5425 gMovieRefCount--; 5426 } 5427 ckfree((char *) movPtr->tmpMovieRecordPtr); 5428 movPtr->tmpMovieRecordPtr = NULL; 5429} 5430 5431/* 5432 *---------------------------------------------------------------------- 5433 * 5434 * MoviePlayerWorldChanged -- 5435 * 5436 * Something changed, arange for the movie to be redisplayed. 5437 * Find its geometry including any movie controller, and request 5438 * this size from Tk. 5439 * 5440 * Results: 5441 * None. 5442 * 5443 * Side effects: 5444 * Movie widget displayed sometime in the future. 5445 * 5446 *---------------------------------------------------------------------- 5447 */ 5448 5449void 5450MoviePlayerWorldChanged (ClientData instanceData) 5451{ 5452 MoviePlayer *movPtr = (MoviePlayer *) instanceData; 5453 Rect aRect; 5454 5455 QTTclDebugPrintf( movPtr->interp, 2, "MoviePlayerWorldChanged" ); 5456 { 5457 GWorldPtr destPort = NULL; 5458 5459 GetMovieGWorld( movPtr->aMovie, &destPort, NULL ); 5460 QTTclDebugPrintf( movPtr->interp, 4, "\tGetMovieGWorld=0x%.8x", destPort ); 5461 } 5462 if (movPtr->tkwin && Tk_IsMapped(movPtr->tkwin) && !(movPtr->flags & REDRAW_PENDING)) { 5463 Tcl_DoWhenIdle( DisplayMovie, (ClientData) movPtr ); 5464 movPtr->flags |= REDRAW_PENDING; 5465 } 5466 5467 if (movPtr->aMovie == NULL) { 5468 return; 5469 } 5470 5471 /* 5472 * Cache info about visual or not; Windows need to serve unmapped audio only movies. 5473 */ 5474 5475 if (GetMovieIndTrackType( movPtr->aMovie, 1, VisualMediaCharacteristic, 5476 movieTrackCharacteristic ) == NULL) { 5477 movPtr->isVisual = 0; 5478 } else { 5479 movPtr->isVisual = 1; 5480 } 5481 5482 if ((movPtr->state & kQTTclMovieStateAsyncLoading) && 5483 (movPtr->loadState < kMovieLoadStatePlayable)) { 5484 5485 /* 5486 * During the first stage of async loading we give it a default size (compare frame). 5487 */ 5488 5489 Tk_GeometryRequest( movPtr->tkwin, 1, 1 ); 5490 Tk_SetInternalBorder( movPtr->tkwin, 0 ); 5491 5492 } else { 5493 5494 /* 5495 * It may happen that a movie controller is not added in 'ConfigureMoviePlayer', 5496 * for instance if we start creating an empty movie with 'Movie .m', and then 5497 * pastes data into it. 5498 */ 5499 5500 AddOrRemoveMovieController( movPtr ); 5501 5502 /* 5503 * Get the total size requested, with or without a controller. 5504 */ 5505 5506 aRect.left = 0; 5507 aRect.top = 0; 5508 aRect.right = movPtr->mwidth; 5509 aRect.bottom = movPtr->mheight; 5510 if (movPtr->wantController && movPtr->aController != NULL) { 5511 MCGetControllerBoundsRect( movPtr->aController, &aRect ); 5512 } else if (movPtr->aMovie != NULL) { // testing... 5513 GetMovieBox( movPtr->aMovie, &aRect ); 5514 } 5515 MacOffsetRect( &aRect, (short) -aRect.left, (short) -aRect.top ); 5516 5517 QTTclDebugPrintf( movPtr->interp, 2, "\taRect.right=%d, aRect.bottom=%d", 5518 aRect.right, aRect.bottom ); 5519 5520 /* 5521 * If any requested particular size (different from the default 0), 5522 * adjust the rectangle size here. 5523 */ 5524 5525 if (movPtr->width) { 5526 aRect.right = movPtr->width; 5527 } 5528 if (movPtr->height) { 5529 aRect.bottom = movPtr->height; 5530 } 5531 5532 /* 5533 * What if any ->width or ->height equal to zero? Get natural size instead! 5534 */ 5535 5536 if (movPtr->width == 0) { 5537 if (movPtr->wantController && movPtr->aController != NULL) { 5538 if (movPtr->mwidth == 0) { 5539 aRect.right = CONTROLLER_WIDTH; /* bad!!! */ 5540 } else { 5541 aRect.right = movPtr->mwidth; 5542 } 5543 } else { 5544 aRect.right = movPtr->mwidth; 5545 } 5546 } 5547 if (movPtr->height == 0) { 5548 if (movPtr->wantController && movPtr->aController != NULL) { 5549 aRect.bottom = movPtr->mheight + movPtr->controllerHeight; 5550 } else { 5551 aRect.bottom = movPtr->mheight; 5552 } 5553 } 5554 5555 /* Padding not supported for the moment. */ 5556 aRect.right += 2 * movPtr->padx + 2 * movPtr->highlightWidth; 5557 aRect.bottom += 2 * movPtr->pady + 2 * movPtr->highlightWidth; 5558 5559 Tk_GeometryRequest( movPtr->tkwin, aRect.right, aRect.bottom ); 5560 //Tk_SetInternalBorder( movPtr->tkwin, movPtr->highlightWidth ); 5561 movPtr->flags |= NEWGWORLD; 5562 5563 QTTclDebugPrintf( movPtr->interp, 2, "\treq size width=%d, height=%d", 5564 aRect.right, aRect.bottom ); 5565 } // end if not kQTTclMovieStateAsyncLoading 5566} 5567 5568/* 5569 *---------------------------------------------------------------------- 5570 * 5571 * CreateMoviePlayer -- 5572 * 5573 * Create a MoviePlayer Object. 5574 * 5575 * Results: 5576 * Return pointer to movieplayer object 5577 * 5578 * Side effects: 5579 * Memory allocated 5580 * 5581 *---------------------------------------------------------------------- 5582 */ 5583 5584static MoviePlayer * 5585CreateMoviePlayer( Tk_Window tkwin ) 5586{ 5587 MoviePlayer *movPtr; 5588 5589 movPtr = (MoviePlayer *) ckalloc( sizeof(MoviePlayer) ); 5590 memset( (void *) movPtr, 0, sizeof(MoviePlayer) ); 5591 movPtr->trackSelect = (TrackSelection *) ckalloc( sizeof(TrackSelection) ); 5592 return movPtr; 5593} 5594 5595/* 5596 *---------------------------------------------------------------------- 5597 * 5598 * AddOrRemoveMovieController -- 5599 * 5600 * Attach any controller. Many of the configure options need a 5601 * controller to work, and therefore we cannot wait to make the 5602 * controller until it is displayed. 5603 * 5604 * Results: 5605 * None 5606 * 5607 * Side effects: 5608 * Controller created and attached, or disposed for the 5609 * corresponding movie. 5610 * 5611 *---------------------------------------------------------------------- 5612 */ 5613 5614static void 5615AddOrRemoveMovieController( MoviePlayer *movPtr ) 5616{ 5617 Rect aRect; 5618 5619 if (movPtr->aMovie != NULL) { 5620 if (!movPtr->wantController && (movPtr->aController != NULL)) { 5621 DisposeMovieController( movPtr->aController ); 5622 movPtr->aController = NULL; 5623 movPtr->flags |= NEWGWORLD; 5624 movPtr->controllerHeight = 0; 5625 } 5626 if (movPtr->wantController && (movPtr->aController == NULL)) { 5627 GWorldPtr theGWorldPtr = NULL; 5628 5629 /* 5630 * It appears to be a bug on Mac OS X that creating the controller 5631 * resets the movies GWorld to current port. Added workaround. 5632 */ 5633 5634 GetMovieBox( movPtr->aMovie, &aRect ); 5635 GetMovieGWorld( movPtr->aMovie, &theGWorldPtr, NULL ); 5636 movPtr->aController = NewMovieController( movPtr->aMovie, &aRect, 5637 mcTopLeftMovie ); 5638 MCSetControllerPort( movPtr->aController, theGWorldPtr ); 5639 if (movPtr->mcEdit) { 5640 MCEnableEditing( movPtr->aController, true ); 5641 } 5642 movPtr->controllerHeight = GetControllerBarHeight( movPtr->aController ); 5643 movPtr->flags |= NEWGWORLD; 5644 } 5645 } 5646} 5647 5648/* 5649 *---------------------------------------------------------------------- 5650 * 5651 * AddMovieToOpenMovies -- 5652 * 5653 * Add this movie to the global list of open movies. 5654 * 5655 * Results: 5656 * None 5657 * 5658 * Side effects: 5659 * Global movies list updated. 5660 * 5661 *---------------------------------------------------------------------- 5662 */ 5663 5664static void 5665AddMovieToOpenMovies( MoviePlayer *movPtr ) 5666{ 5667 MoviePlayerList *movListPtr = NULL; 5668 5669#if TARGET_API_MAC_CARBON 5670 /* 5671 * If this is the first movie we open on Carbon, be sure to set a timer 5672 * to serve it and all that may follow. 5673 */ 5674 5675 if (gCarbonMovieTimerRef == NULL) { 5676 InstallMovieIdlingEventLoopTimer(); 5677 } 5678#endif 5679 5680 QTTclDebugPrintf( movPtr->interp, 2, "AddMovieToOpenMovies: movPtr=%d", movPtr ); 5681 5682 /* 5683 * Search to see if already in our list. If not, then add it. 5684 * gMoviePlayerListPtr always points to the first node, or NULL if none. 5685 */ 5686 5687 movListPtr = gMoviePlayerListPtr; 5688 while ((movListPtr != NULL) && (movPtr != movListPtr->movPtr)) { 5689 movListPtr = movListPtr->next; 5690 } 5691 if (movListPtr == NULL) { 5692 MoviePlayerList *newMovListPtr = NULL; 5693 5694 /* Add as first in list (simplest!). */ 5695 newMovListPtr = (MoviePlayerList *) ckalloc( sizeof(MoviePlayerList) ); 5696 newMovListPtr->movPtr = movPtr; 5697 newMovListPtr->prev = NULL; 5698 newMovListPtr->next = gMoviePlayerListPtr; 5699 if (gMoviePlayerListPtr != NULL) { 5700 gMoviePlayerListPtr->prev = newMovListPtr; 5701 } 5702 gMoviePlayerListPtr = newMovListPtr; 5703 } 5704} 5705 5706static void 5707RemoveMovieFromOpenMovies( MoviePlayer *movPtr ) 5708{ 5709 MoviePlayerList *movListPtr = NULL; 5710 5711 QTTclDebugPrintf( movPtr->interp, 2, "RemoveMovieFromOpenMovies: movPtr=%d", movPtr ); 5712 5713 /* 5714 * Search to see if in our list. If then remove it. 5715 */ 5716 5717 movListPtr = gMoviePlayerListPtr; 5718 while ((movListPtr != NULL) && (movPtr != movListPtr->movPtr)) { 5719 movListPtr = movListPtr->next; 5720 } 5721 if (movListPtr != NULL) { 5722 if (movListPtr->prev != NULL) { 5723 movListPtr->prev->next = movListPtr->next; 5724 } else { 5725 gMoviePlayerListPtr = movListPtr->next; 5726 } 5727 if (movListPtr->next != NULL) { 5728 movListPtr->next->prev = movListPtr->prev; 5729 } 5730 ckfree( (char *) movListPtr ); 5731 } 5732 5733#if TARGET_API_MAC_CARBON 5734 /* 5735 * If this is the last movie we have on Carbon, be sure to remove the timer. 5736 */ 5737 5738 if (gMoviePlayerListPtr == NULL) { 5739 QTUninstallNextTaskNeededSoonerCallback( 5740 NewQTNextTaskNeededSoonerCallbackUPP( TaskNeededSoonerCallback ), 5741 (void *) gCarbonMovieTimerRef ); 5742 RemoveEventLoopTimer( gCarbonMovieTimerRef ); 5743 gCarbonMovieTimerRef = NULL; 5744 } 5745#endif 5746} 5747 5748/* 5749 *---------------------------------------------------------------------- 5750 * 5751 * DisplayMovie -- 5752 * 5753 * Display a movie. 5754 * 5755 * Results: 5756 * None. 5757 * 5758 * Side effects: 5759 * With luck, the movie is displayed 5760 * 5761 *---------------------------------------------------------------------- 5762 */ 5763 5764static void 5765DisplayMovie( ClientData clientData ) 5766{ 5767 MoviePlayer *movPtr = (MoviePlayer *) clientData; 5768 Tk_Window tkwin = movPtr->tkwin; 5769 CGrafPtr saveWorld = NULL; 5770 GDHandle saveDevice = NULL; 5771 GWorldPtr theGWorldPtr = NULL; 5772 Rect aRect; 5773 static RgnHandle region = NULL; 5774 static RgnHandle saveRegion = NULL; 5775 RgnHandle regionHand = NULL; 5776 5777 /* The first time we allocate a region to help us with update events. */ 5778 if (region == NULL) { 5779 region = NewRgn(); 5780 } 5781 if (saveRegion == NULL) { 5782 saveRegion = NewRgn(); 5783 } 5784 QTTclDebugPrintf( movPtr->interp, 2, 5785 "DisplayMovie: flags=%1d%1d%1d%1d%d%d", 5786 (movPtr->flags >> 5) & 0x1, (movPtr->flags >> 4) & 0x1, 5787 (movPtr->flags >> 3) & 0x1, (movPtr->flags >> 2) & 0x1, 5788 (movPtr->flags >> 1) & 0x1, (movPtr->flags >> 0) & 0x1 ); 5789 5790 /* 5791 * Are we ready to display. Clear the redraw pending state. 5792 */ 5793 5794 movPtr->flags &= ~REDRAW_PENDING; 5795 if ((movPtr->flags & MOVIE_DELETED) || !Tk_IsMapped(tkwin)) { 5796 return; 5797 } 5798 if ((movPtr->state & kQTTclMovieStateAsyncLoading) && 5799 (movPtr->loadState < kMovieLoadStatePlayable)) { 5800 5801 /* If we are async loading and not yet playable. */ 5802 return; 5803 } 5804 GetGWorld( &saveWorld, &saveDevice ); 5805 5806 /* 5807 * Tk drawing: Draw the focus highlight if any. 5808 */ 5809 5810 if (movPtr->highlightWidth > 0) { 5811 GC fgGC, bgGC; 5812 Pixmap pixmap; 5813 5814 pixmap = (Pixmap) Tk_WindowId(tkwin); 5815 bgGC = Tk_GCForColor( movPtr->highlightBgColorPtr, pixmap ); 5816 if (movPtr->flags & GOT_FOCUS) { 5817 fgGC = Tk_GCForColor( movPtr->highlightColorPtr, pixmap ); 5818 TkpDrawHighlightBorder( tkwin, fgGC, bgGC, movPtr->highlightWidth, pixmap ); 5819 } else { 5820 TkpDrawHighlightBorder( tkwin, bgGC, bgGC, movPtr->highlightWidth, pixmap ); 5821 } 5822 } 5823 5824 if (movPtr->aMovie != NULL) { 5825 movPtr->display->request++; 5826 5827 theGWorldPtr = QTTclMacGetDrawablePort( Tk_WindowId( tkwin ) ); 5828 SetGWorld( theGWorldPtr, NULL ); 5829 GetClip( saveRegion ); 5830 QTTclMacWinBounds( (TkWindow *) tkwin, &aRect ); 5831 5832 aRect.top += movPtr->inset; 5833 aRect.bottom -= movPtr->inset; 5834 aRect.left += movPtr->inset; 5835 aRect.right -= movPtr->inset; 5836 5837 if (movPtr->flags & NEWGWORLD) { 5838 5839 /* 5840 * It is first when the movie is to be displayed we know which graphics 5841 * port it should be associated with. 5842 * The 'SetMovieGWorld' is costy so set it only if the graphics port 5843 * actually changed. Bug: even if changed the address may be the same? 5844 */ 5845 5846 if ((movPtr->grafPtr == NULL) || (movPtr->grafPtr != theGWorldPtr)) { 5847 SetMovieGWorld( movPtr->aMovie, theGWorldPtr, NULL ); 5848 movPtr->grafPtr = theGWorldPtr; 5849 QTTclDebugPrintf( movPtr->interp, 3, "\tSetMovieGWorld()" ); 5850 } 5851 if (movPtr->aController != NULL) { 5852 MCSetControllerPort( movPtr->aController, theGWorldPtr ); 5853 } 5854 5855 /* 5856 * Be sure to set the movie active here, only to be really sure. 5857 */ 5858 5859 SetMovieActive( movPtr->aMovie, true ); 5860 5861 /* 5862 * We should determine if the toplevel is an actice window or not. 5863 * If not, deactivate the controller. Once this initial state is set correctly, 5864 * the controller seems to get these events and set its correct state automatically. 5865 */ 5866 5867#if TARGET_OS_MAC 5868 QTTclDebugPrintf( movPtr->interp, 3, "\tMyIsToplevelInFront %d", 5869 MyIsToplevelInFront( tkwin ) ); 5870 5871 if (movPtr->aController != NULL) { 5872 if (MyIsToplevelInFront( tkwin )) { 5873 MCDoAction( movPtr->aController, mcActionActivate, NULL ); 5874 } else { 5875 MCDoAction( movPtr->aController, mcActionDeactivate, NULL ); 5876 } 5877 MCMovieChanged( movPtr->aController, movPtr->aMovie ); 5878 } 5879#endif // TARGET_OS_MAC 5880 5881#if TARGET_OS_MAC // Windows should manage this automatically through its subwindows. 5882 5883 /* 5884 * Setup clipping region. Need to check in the event loop if something happened that 5885 * changed the clipping region. Once a clipping region has been set it is valid 5886 * for the lifetime of the movie. 5887 * The clipping regions for the window and its children are 5888 * marked invalid. (Make sure they are valid before drawing.) 5889 */ 5890 5891#if TARGET_API_MAC_CARBON 5892 TkMacOSXInvalClipRgns( ((TkWindow *) (movPtr->tkwin))->privatePtr->winPtr->parentPtr ); 5893#else 5894 TkMacInvalClipRgns( ((TkWindow *) (movPtr->tkwin))->privatePtr->winPtr->parentPtr ); 5895#endif 5896 regionHand = QTTclMacVisableClipRgn( ((TkWindow *) (movPtr->tkwin)) ); 5897 if (movPtr->aController != NULL) { 5898 MCSetClip( movPtr->aController, regionHand, NULL ); 5899 } else { 5900 SetMovieDisplayClipRgn( movPtr->aMovie, regionHand ); 5901 } 5902#endif // TARGET_OS_MAC 5903 5904 /* 5905 * Add movie to our list of displayed movies only if it's not there already. 5906 */ 5907 5908 AddMovieToOpenMovies( movPtr ); 5909 movPtr->state |= kQTTclMovieStateOnDisplay; 5910 movPtr->flags &= ~NEWGWORLD; 5911 } // end NEWGWORLD 5912 5913 if ((movPtr->flags & UPDATEMOVIE) && (movPtr->aController == NULL)) { 5914 5915 /* 5916 * 'MCIsPlayerEvent' takes care of update (Expose) events 5917 * via the controller. 5918 * InvalidateMovieRegion is the preferred way to treat update events 5919 * when there is no controller. Perhaps we could get the exact region that 5920 * needs to be updated and not the complete movie rectangle. 5921 */ 5922 5923#if !TARGET_API_MAC_CARBON 5924 /* The update event this generates is cleared in the mac event loop. */ 5925 RectRgn( region, &aRect ); 5926 InvalidateMovieRegion( movPtr->aMovie, region ); 5927#endif 5928 5929#if TARGET_API_MAC_CARBON 5930 /* 5931 * This triggers a new update event which calls Display() again in an 5932 * infinite loop!!! Never do this! Does not seems to be neeed anyway. 5933 */ 5934 //InvalWindowRect( GetWindowFromPort(theGWorldPtr), &aRect ); 5935#endif 5936 } 5937 movPtr->flags &= ~UPDATEMOVIE; 5938 5939 /* 5940 * Important, set the size and position of the movie in the actual window as 5941 * indicated by TkMacWinBounds above. 5942 */ 5943 5944 if (movPtr->aController != NULL) { 5945 MCSetControllerBoundsRect( movPtr->aController, &aRect ); 5946 } else { 5947 SetMovieBox( movPtr->aMovie, &aRect) ; 5948 } 5949 5950 if (movPtr->flags & NEED_PREROLL) { 5951 // testing... PreRoll'ing should be made as late as possible. First time here. 5952 /* this crashes on Windows for QT 5 5953 PrerollMovie( movPtr->aMovie, GetMovieTime( movPtr->aMovie, NULL ), 5954 GetMoviePreferredRate( movPtr->aMovie ) ); */ 5955 movPtr->flags &= ~NEED_PREROLL; 5956 } 5957 SetClip( saveRegion ); 5958 } 5959 SetGWorld( saveWorld, saveDevice ); 5960} 5961 5962/* 5963 *---------------------------------------------------------------------- 5964 * 5965 * SetMoviePlayerRectBox -- 5966 * 5967 * Sets the movies display rectangle in mac window. 5968 * 5969 * Results: 5970 * None. 5971 * 5972 * Side effects: 5973 * None. 5974 * 5975 *---------------------------------------------------------------------- 5976 */ 5977 5978#if TARGET_OS_MAC 5979static void 5980SetMoviePlayerRectBox( MoviePlayer *movPtr ) 5981{ 5982 Rect aRect; 5983 Rect tkRect; 5984 5985 QTTclMacWinBounds( (TkWindow *) movPtr->tkwin, &tkRect ); 5986 tkRect.left += movPtr->inset; 5987 tkRect.top += movPtr->inset; 5988 tkRect.right -= movPtr->inset; 5989 tkRect.bottom -= movPtr->inset; 5990 if (movPtr->aController != NULL) { 5991 MCGetControllerBoundsRect( movPtr->aController, &aRect ); 5992 if (!MacEqualRect( &tkRect, &aRect )) { 5993 MCSetControllerBoundsRect( movPtr->aController, &tkRect ); 5994 } 5995 } else { 5996 GetMovieBox( movPtr->aMovie, &aRect); 5997 if (!MacEqualRect( &tkRect, &aRect )) { 5998 SetMovieBox( movPtr->aMovie, &tkRect); 5999 } 6000 } 6001} 6002#endif 6003 6004/* 6005 *---------------------------------------------------------------------- 6006 * 6007 * InstallMovieIdlingEventLoopTimer, TaskNeededSoonerCallback, 6008 * CarbonTimerNextTime -- 6009 * 6010 * Sets up Carbon timers to serve movies. 6011 * 6012 * Results: 6013 * . 6014 * 6015 * Side effects: 6016 * Timers installed etc. 6017 * 6018 *---------------------------------------------------------------------- 6019 */ 6020 6021#if TARGET_API_MAC_CARBON 6022static OSStatus 6023InstallMovieIdlingEventLoopTimer( void ) 6024{ 6025 OSStatus err; 6026 6027 err = InstallEventLoopTimer( GetMainEventLoop(), 6028 0, /* firedelay */ 6029 kEventDurationMillisecond * kMinimumIdleDurationInMillis, /* interval */ 6030 NewEventLoopTimerUPP( MoviePlayerCarbonTimer ), 6031 NULL, 6032 &gCarbonMovieTimerRef ); 6033 if (err != noErr) { 6034 /* 6035 * Install a callback that the Idle Manager will use when 6036 * QuickTime needs to wake me up immediately. 6037 */ 6038 6039 err = QTInstallNextTaskNeededSoonerCallback( 6040 NewQTNextTaskNeededSoonerCallbackUPP( TaskNeededSoonerCallback ), 6041 1000, /* Millisecond timescale */ 6042 0, /* No flags */ 6043 (void *) gCarbonMovieTimerRef ); 6044 } 6045 return err; 6046} 6047 6048static void 6049TaskNeededSoonerCallback( TimeValue duration, 6050 unsigned long flags, 6051 void *refcon ) 6052{ 6053 SetEventLoopTimerNextFireTime( (EventLoopTimerRef) refcon, 6054 duration * kEventDurationMillisecond ); 6055} 6056 6057static void 6058CarbonTimerNextTime( void ) 6059{ 6060 OSStatus err = noErr; 6061 long durationMillis; 6062 6063 err = QTGetTimeUntilNextTask( &durationMillis, 1000 ); 6064 if (durationMillis == 0) { 6065 durationMillis = kMinimumIdleDurationInMillis; 6066 } 6067 // testing... 6068 /* This is only a temporary workaround for missing events 6069 * when movie is without a controller. 6070 */ 6071 durationMillis = 50; 6072 // end testing... 6073 6074 SetEventLoopTimerNextFireTime( gCarbonMovieTimerRef, 6075 durationMillis * kEventDurationMillisecond ); 6076} 6077 6078#endif 6079 6080/* 6081 *---------------------------------------------------------------------- 6082 * 6083 * MoviePlayerCarbonTimer -- 6084 * 6085 * Timer callback to serve movies under Carbon. 6086 * 6087 * Results: 6088 * None. 6089 * 6090 * Side effects: 6091 * Calls 'MoviePlayerMacEvent'. 6092 * 6093 *---------------------------------------------------------------------- 6094 */ 6095 6096#if TARGET_API_MAC_CARBON 6097static pascal void 6098MoviePlayerCarbonTimer( EventLoopTimerRef theTimer, 6099 void *userData ) 6100{ 6101 /* 6102 * The first NULL (EventRecord *) just says idle movie. 6103 * The second NULL says idle all movies. 6104 */ 6105 6106 MoviePlayerMacEvent( NULL, NULL ); 6107} 6108#endif 6109 6110/* 6111 *---------------------------------------------------------------------- 6112 * 6113 * InstallCarbonWindowEventHandler, 6114 * MovieDestroyCarbonWindowHandlerCleanup -- 6115 * 6116 * Makes sure that there is always a Carbon window event handler. 6117 * Removed when not useful anymore. 6118 * 6119 * Results: 6120 * None. 6121 * 6122 * Side effects: 6123 * May install or remove Carbon window event handler. 6124 * 6125 *---------------------------------------------------------------------- 6126 */ 6127 6128#if TARGET_API_MAC_CARBON 6129static void 6130InstallCarbonWindowEventHandler( MoviePlayer *movPtr ) 6131{ 6132 WindowRef windowRef; /* identical to WindowPtr */ 6133 EventHandlerRef handlerRef; 6134 OSStatus err; 6135 Tcl_HashEntry *hashPtr = NULL; 6136 CarbonWindowHandlerEntry *entryPtr; 6137 int isNew; 6138 const EventTypeSpec kEvents[] = { 6139 {kEventClassWindow, kEventWindowUpdate}, 6140 {kEventClassWindow, kEventWindowActivated}, 6141 {kEventClassWindow, kEventWindowDeactivated}, 6142 {kEventClassMouse, kEventMouseDown}, 6143 {kEventClassMouse, kEventMouseUp}, 6144 {kEventClassMouse, kEventMouseDragged} /* Needed in controller, 6145 * volume, and panos. */ 6146 }; 6147 6148 /* 6149 * We shall keep a single carbon window event handler for each toplevel 6150 * window that contains a displayed movie. 6151 */ 6152 6153 if (gCarbonWindowHandlerHashPtr == NULL) { 6154 gCarbonWindowHandlerHashPtr = (Tcl_HashTable *) ckalloc( sizeof(Tcl_HashTable) ); 6155 Tcl_InitHashTable( gCarbonWindowHandlerHashPtr, TCL_ONE_WORD_KEYS ); 6156 } 6157 windowRef = GetWindowFromPort( TkMacOSXGetDrawablePort( Tk_WindowId(movPtr->tkwin)) ); 6158 6159 /* 6160 * If already in our hash table, just add a refCount, else create it. 6161 */ 6162 6163 hashPtr = Tcl_FindHashEntry( gCarbonWindowHandlerHashPtr, (char *) windowRef ); 6164 if (hashPtr != NULL) { 6165 entryPtr = (CarbonWindowHandlerEntry *) Tcl_GetHashValue( hashPtr ); 6166 entryPtr->refCount++; 6167 6168 QTTclDebugPrintf( movPtr->interp, 2, 6169 "InstallCarbonWindowEventHandler: (exists) refCount=%d, windowRef=0x%.8x", 6170 entryPtr->refCount, windowRef ); 6171 } else { 6172 err = InstallWindowEventHandler( windowRef, 6173 NewEventHandlerUPP( MovieCarbonWindowEventHandler ), 6174 GetEventTypeCount(kEvents), 6175 &kEvents, /* const EventTypeSpec* */ 6176 (void *) movPtr, &handlerRef ); 6177 if (err == noErr) { 6178 entryPtr = (CarbonWindowHandlerEntry *) ckalloc( sizeof(CarbonWindowHandlerEntry) ); 6179 entryPtr->handlerRef = handlerRef; 6180 entryPtr->refCount = 1; 6181 hashPtr = Tcl_CreateHashEntry( gCarbonWindowHandlerHashPtr, 6182 (char *) windowRef, &isNew ); 6183 Tcl_SetHashValue( hashPtr, entryPtr ); 6184 } 6185 QTTclDebugPrintf( movPtr->interp, 2, 6186 "InstallCarbonWindowEventHandler: (new) refCount=%d, windowRef=0x%.8x", 6187 entryPtr->refCount, windowRef ); 6188 } 6189} 6190#endif 6191 6192#if TARGET_API_MAC_CARBON 6193static void 6194MovieDestroyCarbonWindowHandlerCleanup( MoviePlayer *movPtr ) 6195{ 6196 WindowRef windowRef = NULL; /* identical to WindowPtr */ 6197 Tcl_HashEntry *hashPtr = NULL; 6198 CarbonWindowHandlerEntry *entryPtr; 6199 OSStatus err = noErr; 6200 6201 QTTclDebugPrintf( movPtr->interp, 2, 6202 "MovieDestroyCarbonWindowHandlerCleanup: gCarbonWindowHandlerHashPtr=%d", 6203 gCarbonWindowHandlerHashPtr ); 6204 if (gCarbonWindowHandlerHashPtr == NULL) { 6205 return; 6206 } 6207 if (movPtr->tkwin == NULL) { 6208 return; 6209 } 6210 windowRef = GetWindowFromPort( TkMacOSXGetDrawablePort( Tk_WindowId(movPtr->tkwin)) ); 6211 if (windowRef == NULL) { 6212 return; 6213 } 6214 hashPtr = Tcl_FindHashEntry( gCarbonWindowHandlerHashPtr, (char *) windowRef ); 6215 if (hashPtr == NULL) { 6216 return; 6217 } 6218 entryPtr = Tcl_GetHashValue( hashPtr ); 6219 entryPtr->refCount--; 6220 6221 QTTclDebugPrintf( movPtr->interp, 2, "\trefCount=%d, windowRef=0x%.8x", 6222 entryPtr->refCount, windowRef ); 6223 6224 if (entryPtr->refCount <= 0) { 6225 6226 /* 6227 * No more movies in this mac window; remove event handler. 6228 */ 6229 6230 err = RemoveEventHandler( entryPtr->handlerRef ); 6231 ckfree( (char *) entryPtr ); 6232 Tcl_DeleteHashEntry( hashPtr ); 6233 } 6234} 6235#endif 6236 6237/* 6238 *---------------------------------------------------------------------- 6239 * 6240 * MovieCarbonWindowEventHandler -- 6241 * 6242 * Carbon window event handler for the Movie Player. Not related to 6243 * the Carbon timers. 6244 * 6245 * Results: 6246 * OSStatus if event handled or not. 6247 * 6248 * Side effects: 6249 * Depending on the event. 6250 * 6251 *---------------------------------------------------------------------- 6252 */ 6253 6254#if TARGET_API_MAC_CARBON 6255static OSStatus 6256MovieCarbonWindowEventHandler( EventHandlerCallRef callRef, 6257 EventRef eventRef, 6258 void *userData ) 6259{ 6260 MoviePlayer *movPtr = (MoviePlayer *) userData; 6261 OSStatus returnOSStatus = eventNotHandledErr; 6262 EventRecord eventRec; 6263 WindowRef windowRef = NULL; 6264 OSStatus err = noErr; 6265 6266 /* Lots of temporary debug stuff. */ 6267 UInt32 eventClass; 6268 UInt32 eventKind; 6269 char tmp1[64]; 6270 char tmp2[64]; 6271 6272 QTTclDebugPrintf( movPtr->interp, 3, 6273 "MovieCarbonWindowEventHandler: movPtr->tkwin=%d", movPtr->tkwin ); 6274 6275 /* We are being destroyed. */ 6276 if (movPtr->flags & MOVIE_DELETED) { 6277 return returnOSStatus; 6278 } 6279 eventClass = GetEventClass( eventRef ); 6280 eventKind = GetEventKind( eventRef ); 6281 memset( tmp1, 0, 64 ); 6282 memcpy( tmp1, &eventClass, 4 ); 6283 6284 switch (eventClass) { 6285 case kEventClassWindow: { 6286 6287 err = GetEventParameter( eventRef, kEventParamDirectObject, typeWindowRef, 6288 NULL, sizeof(windowRef), NULL, &windowRef ); 6289 6290 switch (eventKind) { 6291 case kEventWindowDrawContent: strcpy( tmp2, "kEventWindowDrawContent" ); break; 6292 case kEventWindowUpdate: strcpy( tmp2, "kEventWindowUpdate" ); break; 6293 case kEventWindowActivated: strcpy( tmp2, "kEventWindowActivated" ); break; 6294 case kEventWindowDeactivated: strcpy( tmp2, "kEventWindowDeactivated" ); break; 6295 } 6296 break; 6297 } 6298 case kEventClassMouse: { 6299 6300 err = GetEventParameter( eventRef, kEventParamWindowRef, typeWindowRef, 6301 NULL, sizeof(windowRef), NULL, &windowRef ); 6302 6303 switch (eventKind) { 6304 case kEventMouseDown: strcpy( tmp2, "kEventMouseDown" ); break; 6305 case kEventMouseUp: strcpy( tmp2, "kEventMouseUp" ); break; 6306 case kEventMouseDragged: strcpy( tmp2, "kEventMouseDragged" ); break; 6307 } 6308 break; 6309 } 6310 } 6311 6312 QTTclDebugPrintf( movPtr->interp, 3, "\twindowRef=0x%.8x %s %s", 6313 windowRef, tmp1, tmp2 ); 6314 6315 if (err == noErr) { 6316 ConvertEventRefToEventRecord( eventRef, &eventRec ); 6317 MoviePlayerMacEvent( &eventRec, windowRef ); 6318 } 6319 return returnOSStatus; 6320} 6321#endif 6322 6323/* 6324 *---------------------------------------------------------------------- 6325 * 6326 * MoviePlayerMacEvent -- 6327 * 6328 * Processes mac events. Gets events until none of them are used by 6329 * any movies or dialogs (Mac). 6330 * Update (Expose) events for a movie without a controller are 6331 * dealt with here. 6332 * 6333 * Results: 6334 * 0 if the event was not handled, 1 if it was. 6335 * 6336 * Side effects: 6337 * Events processed. 6338 * 6339 *---------------------------------------------------------------------- 6340 */ 6341 6342#if TARGET_OS_MAC 6343 6344static int 6345MoviePlayerMacEvent( 6346 EventRecord *eventPtr, /* If NULL just idle movie. */ 6347 WindowRef serveWindowRef ) /* If NULL serve all movies in our list, 6348 * else serve only movies in this mac 6349 * window. */ 6350{ 6351 MoviePlayer *movPtr; 6352 Movie theMovie = NULL; 6353 MoviePlayerList *movListPtr = NULL; 6354 MoviePlayerList *nextMovListPtr = NULL; 6355 GWorldPtr saveWorld = NULL; 6356 GDHandle saveDevice = NULL; 6357 GWorldPtr destPort = NULL; 6358 Rect aRect; 6359 int eventDone = false; 6360 int clipInvalid = false; 6361 long maxMilliSecsToUse = 0; 6362 static long counter = 0; 6363 static RgnHandle saveRegion = NULL; 6364 static RgnHandle region = NULL; 6365 RgnHandle rgnHandle = NULL; 6366#if TARGET_API_MAC_CARBON 6367 int shortcutLoop = false; 6368#else 6369 /* if true we get mac events in a shortcut loop; never on Mac OS X */ 6370 int shortcutLoop = true; 6371#endif 6372 6373 if (saveRegion == NULL) { 6374 saveRegion = NewRgn(); 6375 } 6376 if (region == NULL) { 6377 region = NewRgn(); 6378 } 6379 6380 /* 6381 * We keep a counter here to enable regular calls only at a fraction rate. 6382 * This is used for queries to the status when a movie is loaded remotely. 6383 */ 6384 6385 counter++; 6386 6387 /* 6388 * Mac: process the incoming event, if movie player event, poll for new 6389 * events, handle them, until we get an event not aimed for us. See 'shortcutLoop'. 6390 * See "Inside Macintosh: QuickTime Components", p. 2-46. 6391 * Potentially dangerous??? 6392 */ 6393 6394 do { 6395 eventDone = false; 6396 6397 /* 6398 * See if the event is meant for the effects parameter dialog box. 6399 */ 6400 6401 if (eventPtr != NULL) { 6402 eventDone = EffectsHandleDialogEvents( eventPtr, 0 ); 6403 } 6404 6405 if (!eventDone) { 6406 GetGWorld( &saveWorld, &saveDevice ); 6407 6408 movListPtr = gMoviePlayerListPtr; 6409 while (movListPtr != NULL) { 6410 movPtr = movListPtr->movPtr; 6411 nextMovListPtr = movListPtr->next; 6412 theMovie = movPtr->aMovie; 6413 6414 if (movPtr->state & kQTTclMovieStateOnDisplay) { 6415 if (movPtr->flags & MOVIE_DELETED) { 6416 goto nextMovie; 6417 } 6418 if (serveWindowRef != NULL) { 6419 6420 /* 6421 * Serve only movies in specified mac window. 6422 */ 6423 6424 if (GetWindowFromPort( movPtr->grafPtr ) != serveWindowRef) { 6425 goto nextMovie; 6426 } 6427 } 6428 GetMovieGWorld( theMovie, &destPort, NULL ); 6429 SetGWorld( destPort, NULL ); 6430 GetClip( saveRegion ); 6431 6432 /* 6433 * The 'ClipRect' affects the clipping of the controller, and must 6434 * encompass it to get it drawn correctly. 6435 * 'MCSetClip/SetMovieDisplayClipRgn' then sets the clipping of the 6436 * actual movie. 6437 * Setting clip here is absolutely necessary to get the controller drawn! 6438 * BUG: if another widget 'place'ed on top of controller => inf loop; 6439 * has something to do with clipping, test 'clipInvalid = false;'. 6440 */ 6441 6442 QTTclMacWinBounds( (TkWindow *) movPtr->tkwin, &aRect ); 6443 RectRgn( region, &aRect ); 6444 SetClip( region ); 6445 clipInvalid = false; 6446 6447 /* 6448 * We must find out if the present clip region for the movie is invalid, 6449 * and set a new one below if this is the case. 6450 */ 6451 6452 if (MyIsClipRegionInvalid( movPtr->tkwin )) { 6453 clipInvalid = true; 6454 QTTclDebugPrintf( movPtr->interp, 3, "\tMyIsClipRegionInvalid" ); 6455 } 6456 TkMacOSXSetUpClippingRgn( (Drawable) Tk_WindowId( movPtr->tkwin ) ); 6457 if (clipInvalid) { 6458 rgnHandle = QTTclMacVisableClipRgn( (TkWindow *) movPtr->tkwin ); 6459 SetMoviePlayerRectBox( movPtr ); 6460 if (rgnHandle == NULL) { 6461 clipInvalid = false; 6462 } 6463 } 6464 6465 if (movPtr->aController != NULL) { 6466 if (clipInvalid) { 6467 MCSetClip( movPtr->aController, rgnHandle, NULL ); 6468 } 6469 if (eventPtr == NULL) { 6470 6471 /* Says we shall only idle movie. */ 6472 MCIdle( movPtr->aController ); 6473 } else { 6474 if (MCIsPlayerEvent( movPtr->aController, eventPtr )) { 6475 eventDone = 1; 6476 break; 6477 } 6478 } 6479 } else { /* without a controller */ 6480 if (theMovie != NULL) { 6481 6482 /* 6483 * For a movie without a controller, the rate is not reset to 0 6484 * when the movie ends. Needs to do that provided it is not looping. 6485 */ 6486 6487 /* Not working on MacOSX's event model!!! */ 6488 6489 if (!IsMovieLooping( theMovie )) { 6490 if (IsMovieDone( theMovie )) { 6491 if (GetMovieRate( theMovie ) > 0) { 6492 SetMovieRate( theMovie, 0 ); 6493 QTTclDebugPrintf( movPtr->interp, 3, 6494 "\tMovieDone, SetMovieRate 0" ); 6495 } 6496 } 6497 } 6498 if (clipInvalid) { 6499 SetMovieDisplayClipRgn( theMovie, rgnHandle ); 6500 } 6501 MoviesTask( theMovie, maxMilliSecsToUse ); 6502 } 6503 } 6504 if (movPtr->loadCommand && 6505 (movPtr->loadState < kMovieLoadStateComplete)) { 6506 if (counter % 10 == 0) { 6507 CheckMovieLoadState(movPtr); 6508 } 6509 } 6510 SetClip( saveRegion ); 6511 6512 } else if (movPtr->url != NULL) { 6513 6514 /* 6515 * If loading a remote movie (-url) it needs to be served while loading, 6516 * but not displayed. 6517 */ 6518 6519 MoviesTask( theMovie, maxMilliSecsToUse ); 6520 if (movPtr->loadCommand) { 6521 if (counter % 10 == 0) { 6522 CheckMovieLoadState( movPtr ); 6523 } 6524 } 6525 } 6526 6527 nextMovie: 6528 6529 movListPtr = nextMovListPtr; 6530 } /* end loop over movie player list */ 6531 6532 SetGWorld( saveWorld, saveDevice ); 6533 } /* end if !eventDone */ 6534 6535 /* 6536 * We should get all events that are "movie player" events before returning. 6537 * The first event that is not handled by us is passed on. 6538 * We don't do this on Carbon. 6539 */ 6540 6541#if !TARGET_API_MAC_CARBON 6542 if (shortcutLoop && eventDone) { 6543 WaitNextEvent( everyEvent, eventPtr, 0, NULL ); 6544 } 6545#endif 6546 6547 } while (shortcutLoop && eventDone); 6548 6549#if TARGET_API_MAC_CARBON 6550 CarbonTimerNextTime(); 6551#endif 6552 6553 return eventDone; 6554} 6555 6556#endif // TARGET_OS_MAC 6557 6558#ifdef _WIN32 6559/* 6560 *---------------------------------------------------------------------- 6561 * 6562 * QTWinProc -- 6563 * 6564 * This is the window callback procedure for Windows only. 6565 * 6566 * Results: 6567 * Same as the original WinProc. 6568 * 6569 * Side effects: 6570 * First the Mac event procedure called, then the original WinProc. 6571 * 6572 *---------------------------------------------------------------------- 6573 */ 6574 6575LRESULT CALLBACK 6576QTWinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) 6577{ 6578 LONG origProc = 0L; 6579 HWND tempH = NULL; 6580 MoviePlayerList *movListPtr = NULL; 6581 MoviePlayer *movPtr; 6582 6583 if (GetNativeWindowPort(hWnd)) { 6584 MSG msg; 6585 EventRecord macEvent; 6586 LONG thePoint = GetMessagePos(); 6587 int retVal; 6588 6589 msg.hwnd = hWnd; 6590 msg.message = message; 6591 msg.wParam = wParam; 6592 msg.lParam = lParam; 6593 msg.time = GetMessageTime(); 6594 msg.pt.x = LOWORD(thePoint); 6595 msg.pt.y = HIWORD(thePoint); 6596 6597 /* Convert the message to a QTML event */ 6598 WinEventToMacEvent( &msg, &macEvent ); 6599 retVal = MoviePlayerMacEventWin( &macEvent ); 6600 } 6601 6602 /* 6603 * Dispatch the event to the correct original winproc from tk. 6604 */ 6605 6606 movListPtr = gMoviePlayerListPtr; 6607 while (movListPtr != NULL) { 6608 movPtr = movListPtr->movPtr; 6609 if (movPtr->hwnd != NULL) { 6610 if (hWnd == movPtr->hwnd) { 6611 origProc = movPtr->winEventProc; 6612 break; 6613 } 6614 } 6615 movListPtr = movListPtr->next; 6616 } 6617 6618 if (origProc) { 6619 return CallWindowProc( (WNDPROC) origProc, hWnd, message, wParam, lParam ); 6620 } else { 6621 return 0; 6622 } 6623} 6624 6625/* 6626 *---------------------------------------------------------------------- 6627 * 6628 * MoviePlayerMacEventWin -- 6629 * 6630 * Processes mac events. 6631 * Incoming event just filtered through all active movies and 6632 * dialogs (Windows). Just a stripped down version of 6633 * 'MoviePlayerMacEvent'. 6634 * 6635 * Results: 6636 * 0 if the event was not handled, 1 if it was. 6637 * 6638 * Side effects: 6639 * Events processed. 6640 * 6641 *---------------------------------------------------------------------- 6642 */ 6643 6644static int 6645MoviePlayerMacEventWin( EventRecord *eventPtr ) 6646{ 6647 MoviePlayer *movPtr; 6648 Movie theMovie = NULL; 6649 MoviePlayerList *movListPtr = NULL; 6650 MoviePlayerList *nextMovListPtr = NULL; 6651 int eventDone = 0; 6652 static long counter = 0; 6653 long maxMilliSecsToUse = 0; 6654 6655 /* 6656 * We keep a counter here to enable regular calls only at a fraction rate. 6657 * This is used for queries to the status when a movie is loaded remotely. 6658 */ 6659 6660 counter++; 6661 movListPtr = gMoviePlayerListPtr; 6662 6663 while (movListPtr != NULL) { 6664 nextMovListPtr = movListPtr->next; 6665 movPtr = movListPtr->movPtr; 6666 theMovie = movPtr->aMovie; 6667 6668 /* 6669 * Unmapped audio only movies need to be served on Windows, in contrast to Mac. 6670 * The 'isVisual' member variable is cached with info if audio only or not. 6671 */ 6672 6673 if ((movPtr->state & kQTTclMovieStateOnDisplay) || !(movPtr->isVisual)) { 6674 6675 if (movPtr->aController != NULL) { 6676 if (MCIsPlayerEvent( movPtr->aController, eventPtr )) { 6677 eventDone = 1; 6678 } 6679 } else { 6680 if (theMovie != NULL) { 6681 6682 /* 6683 * For a movie without a controller, the rate is not reset to 0 6684 * when the movie ends. Needs to do that provided it is not looping. 6685 */ 6686 6687 if (!IsMovieLooping( theMovie )) { 6688 if (IsMovieDone( theMovie )) { 6689 if (GetMovieRate( theMovie ) > 0) { 6690 SetMovieRate( theMovie, 0 ); 6691 } 6692 } 6693 } 6694 MoviesTask( theMovie, maxMilliSecsToUse ); 6695 } 6696 } 6697 if (movPtr->loadCommand && (movPtr->loadState < kMovieLoadStateComplete)) { 6698 if (counter % 10 == 0) { 6699 CheckMovieLoadState(movPtr); 6700 } 6701 } 6702 6703 } else if (movPtr->url != NULL) { 6704 6705 /* 6706 * If loading a remote movie (-url) it needs to be served while loading, 6707 * but not displayed. 6708 */ 6709 6710 MoviesTask( theMovie, maxMilliSecsToUse ); 6711 6712 /* does this increase the download speed? */ 6713 if (movPtr->loadCommand != NULL) { 6714 if (counter % 10 == 0) { 6715 CheckMovieLoadState( movPtr ); 6716 } 6717 } 6718 } 6719 6720 /* Take next movie in our linked list. */ 6721 movListPtr = nextMovListPtr; 6722 } 6723 return 0; 6724} 6725#endif // _WIN32 6726 6727/* 6728 *---------------------------------------------------------------------- 6729 * 6730 * CheckMovieLoadState -- 6731 * 6732 * During an async opening of a remote movie, we need to 6733 * regularly query the movie's load state. Calls to 'MoviesTask' 6734 * is necessary to keep the network process alive. 6735 * 6736 * Results: 6737 * None. 6738 * 6739 * Side effects: 6740 * Any registered Tcl procedure gets called if the load state changes. 6741 * 6742 *---------------------------------------------------------------------- 6743 */ 6744 6745static void 6746CheckMovieLoadState( MoviePlayer *movPtr ) 6747{ 6748 Tcl_Interp *interp = movPtr->interp; 6749 long loadState = 0; 6750 ComponentResult errStatus; 6751 int resTcl = TCL_OK; 6752 Tcl_Obj *listObjPtr = NULL; 6753 int useDirectCallback = false; 6754 6755 loadState = GetMovieLoadState( movPtr->aMovie ); 6756 6757 if (loadState == movPtr->loadState) { 6758 6759 /* Movies state did not change compared to previous call. */ 6760 return; 6761 } 6762 QTTclDebugPrintf( interp, 2, "CheckMovieLoadState loadState=%d", 6763 loadState ); 6764 6765 /* 6766 * Start designing the Tcl callback. 6767 * Note that movPtr->loadCommand may already be a list. 6768 */ 6769 6770 if (movPtr->loadCommand) { 6771 listObjPtr = Tcl_NewListObj( 0, (Tcl_Obj **) NULL ); 6772 Tcl_ListObjAppendList( interp, listObjPtr, 6773 Tcl_NewStringObj(movPtr->loadCommand, -1) ); 6774 Tcl_ListObjAppendElement( interp, listObjPtr, 6775 Tcl_NewStringObj( Tcl_GetCommandName( interp, movPtr->widgetCmd ), -1 ) ); 6776 } 6777 6778 if ((loadState < 0) || (loadState == kMovieLoadStateError)) { 6779 6780 /* 6781 * We've got an error. Find a way to add both an error code and the message 6782 * to the tcl callback procedure. 'GetMovieStatus' returns errors 6783 * occuring in 'MoviesTask', which is where we are when establishing 6784 * network connections etc. 6785 */ 6786 6787 /* Reset the load state. */ 6788 movPtr->loadState = loadState; 6789 6790 errStatus = GetMovieStatus( movPtr->aMovie, NULL ); 6791 QTTclDebugPrintf( interp, 2, "\t GetMovieStatus errStatus=%d", 6792 errStatus ); 6793 6794 if (movPtr->loadCommand) { 6795 Tcl_ListObjAppendElement( interp, listObjPtr, Tcl_NewStringObj("error", -1) ); 6796 if (errStatus != noErr) { 6797 Tcl_Obj *errObjPtr; 6798 6799 errObjPtr = GetErrorObj( errStatus ); 6800 Tcl_ListObjAppendElement( interp, listObjPtr, errObjPtr ); 6801 } else { 6802 Tcl_ListObjAppendElement( interp, listObjPtr, Tcl_NewLongObj( errStatus ) ); 6803 } 6804 if (useDirectCallback) { 6805 resTcl = Tcl_Eval( interp, Tcl_GetString( listObjPtr ) ); 6806 Tcl_DoOneEvent( TCL_DONT_WAIT | TCL_ALL_EVENTS ); 6807 } 6808 } 6809 6810 } else if (loadState != movPtr->loadState) { 6811 6812 /* Reset the load state. */ 6813 movPtr->loadState = loadState; 6814 6815 if ((loadState >= kMovieLoadStatePlayable) && 6816 !(movPtr->state & kQTTclMovieStateAsyncHasWorld)) { 6817 6818 /* 6819 * Now its time to query the movies size, and add a controller. 6820 * Many of the configure options need a controller to work, 6821 * and therefore we cannot wait to make the controller until it is displayed. 6822 */ 6823 6824 if (movPtr->aMovie != NULL) { 6825 Rect aRect; 6826 6827 GetMovieBox( movPtr->aMovie, &aRect ); 6828 MacOffsetRect( &aRect, (short) -aRect.left, (short) -aRect.top ); 6829 movPtr->mwidth = aRect.right; 6830 movPtr->mheight = aRect.bottom; 6831 6832 /* 6833 * All configuration options are taken from the struct now, 6834 * and we therefore need to force all settings (except -file -url etc). 6835 */ 6836 6837 resTcl = ConfigureMoviePlayer( interp, movPtr, 0, NULL ); 6838 if (resTcl != TCL_OK) { 6839 Tcl_ListObjAppendElement( interp, listObjPtr, 6840 Tcl_NewStringObj("error", -1) ); 6841 Tcl_ListObjAppendElement( interp, listObjPtr, 6842 Tcl_GetObjResult( interp ) ); 6843 6844 if (useDirectCallback) { 6845 resTcl = Tcl_Eval( interp, Tcl_GetString( listObjPtr ) ); 6846 Tcl_DoOneEvent( TCL_DONT_WAIT | TCL_ALL_EVENTS ); 6847 } 6848 return; 6849 } else { 6850 MoviePlayerWorldChanged( (ClientData) movPtr ); 6851 movPtr->state |= kQTTclMovieStateAsyncHasWorld; 6852 } 6853 } 6854 } 6855 if (loadState >= kMovieLoadStateComplete) { 6856 6857 /* 6858 * We are finished with async loading. Clear flag. 6859 */ 6860 6861 movPtr->state &= ~kQTTclMovieStateAsyncLoading; 6862 } 6863 6864 /* 6865 * Load state changed, call Tcl proc. 6866 * Must not be called before 'MoviePlayerWorldChanged'! 6867 */ 6868 6869 if (movPtr->loadCommand) { 6870 if (loadState < kMovieLoadStatePlayable) { 6871 Tcl_ListObjAppendElement( interp, listObjPtr, 6872 Tcl_NewStringObj("loading", -1) ); 6873 } else if (loadState < kMovieLoadStatePlaythroughOK) { 6874 Tcl_ListObjAppendElement( interp, listObjPtr, 6875 Tcl_NewStringObj("playthroughok", -1) ); 6876 } else if (loadState < kMovieLoadStateComplete) { 6877 Tcl_ListObjAppendElement( interp, listObjPtr, 6878 Tcl_NewStringObj("playable", -1) ); 6879 } else if (loadState >= kMovieLoadStateComplete) { 6880 Tcl_ListObjAppendElement( interp, listObjPtr, 6881 Tcl_NewStringObj("complete", -1) ); 6882 } 6883 if (useDirectCallback) { 6884 resTcl = Tcl_Eval( interp, Tcl_GetString( listObjPtr ) ); 6885 Tcl_DoOneEvent( TCL_DONT_WAIT | TCL_ALL_EVENTS ); 6886 } 6887 } 6888 } 6889 if (useDirectCallback) { 6890 Tcl_DecrRefCount( listObjPtr ); 6891 } 6892 6893 /* 6894 * Design an async callback to be executed as soon as possible. 6895 */ 6896 6897 if (!useDirectCallback && listObjPtr != NULL) { 6898 Tcl_HashTable *asyncLoadHashTablePtr = movPtr->asyncLoadHashTablePtr; 6899 Tcl_HashEntry *hashPtr = NULL; 6900 AsyncLoadHandlerEntry *asyncHandlerEntryPtr; 6901 int isNew; 6902 6903 /* Init hash table. */ 6904 if (asyncLoadHashTablePtr == NULL) { 6905 movPtr->asyncLoadHashTablePtr = (Tcl_HashTable *) 6906 ckalloc( sizeof(Tcl_HashTable) ); 6907 asyncLoadHashTablePtr = movPtr->asyncLoadHashTablePtr; 6908 Tcl_InitHashTable( asyncLoadHashTablePtr, TCL_ONE_WORD_KEYS ); 6909 } 6910 6911 /* Create the entry in hash table. */ 6912 asyncHandlerEntryPtr = (AsyncLoadHandlerEntry *) 6913 ckalloc( sizeof(AsyncLoadHandlerEntry) ); 6914 hashPtr = Tcl_CreateHashEntry( asyncLoadHashTablePtr, 6915 (char *) asyncHandlerEntryPtr, &isNew ); 6916 Tcl_SetHashValue( hashPtr, (char *) asyncHandlerEntryPtr ); 6917 asyncHandlerEntryPtr->movPtr = movPtr; 6918 asyncHandlerEntryPtr->commandObjPtr = listObjPtr; 6919 asyncHandlerEntryPtr->hashPtr = hashPtr; 6920 6921 asyncHandlerEntryPtr->timerToken = Tcl_CreateTimerHandler( 0, 6922 AsyncLoadHandlerProc, (ClientData) asyncHandlerEntryPtr ); 6923 } 6924} 6925 6926/* 6927 *---------------------------------------------------------------------- 6928 * 6929 * AsyncLoadHandlerProc -- 6930 * 6931 * Callback when async loading movies. 6932 * 6933 * Results: 6934 * . 6935 * 6936 * Side effects: 6937 * . 6938 * 6939 *---------------------------------------------------------------------- 6940 */ 6941 6942static void 6943AsyncLoadHandlerProc( 6944 ClientData clientData ) /* Pointer to AsyncLoadAsyncHandlerRecord structure. */ 6945{ 6946 AsyncLoadHandlerEntry *asyncHandlerEntryPtr = (AsyncLoadHandlerEntry *) clientData; 6947 Tcl_Interp *interp = asyncHandlerEntryPtr->movPtr->interp; 6948 int cmdCode; 6949 6950 /* Since we may be destroyed in the callback keep storage alive. */ 6951 Tcl_Preserve( (ClientData) asyncHandlerEntryPtr->movPtr ); 6952 6953 if (interp != NULL) { 6954 QTTclDebugPrintf( interp, 2, "AsyncLoadHandlerProc" ); 6955 Tcl_IncrRefCount( asyncHandlerEntryPtr->commandObjPtr ); 6956 cmdCode = Tcl_EvalObjEx( interp, asyncHandlerEntryPtr->commandObjPtr, TCL_EVAL_GLOBAL ); 6957 } else { 6958 /* 6959 * This should not happen, but by definition of how async 6960 * handlers are invoked, it's possible. Better error 6961 * checking is needed here. 6962 */ 6963 } 6964 6965 /* Remove it since it is a single shot call. */ 6966 Tcl_DecrRefCount( asyncHandlerEntryPtr->commandObjPtr ); 6967 Tcl_DeleteHashEntry( asyncHandlerEntryPtr->hashPtr ); 6968 6969 Tcl_Release( (ClientData) asyncHandlerEntryPtr->movPtr ); 6970 6971 ckfree( (char *) asyncHandlerEntryPtr ); 6972} 6973 6974static void 6975AsyncLoadFree( MoviePlayer *movPtr ) 6976{ 6977 Tcl_HashTable *asyncLoadHashTablePtr = movPtr->asyncLoadHashTablePtr; 6978 Tcl_HashEntry *hashPtr; 6979 Tcl_HashSearch search; 6980 AsyncLoadHandlerEntry *entryPtr; 6981 6982 /* Loop through the list of async handler hash entries and kill. */ 6983 if (asyncLoadHashTablePtr != NULL) { 6984 hashPtr = Tcl_FirstHashEntry( asyncLoadHashTablePtr, &search ); 6985 while (hashPtr != NULL) { 6986 entryPtr = (AsyncLoadHandlerEntry *) Tcl_GetHashValue( hashPtr ); 6987 Tcl_DeleteTimerHandler( entryPtr->timerToken ); 6988 Tcl_DecrRefCount( entryPtr->commandObjPtr ); 6989 Tcl_DeleteHashEntry( hashPtr ); 6990 ckfree( (char *) entryPtr ); 6991 hashPtr = Tcl_NextHashEntry( &search ); 6992 } 6993 Tcl_DeleteHashTable( asyncLoadHashTablePtr ); 6994 Tcl_Free( (char *) asyncLoadHashTablePtr ); 6995 movPtr->asyncLoadHashTablePtr = NULL; 6996 } 6997} 6998 6999/* 7000 *---------------------------------------------------------------------- 7001 * 7002 * MovieExitproc -- 7003 * 7004 * Registered exit handler. If no movies left call ExitMoviePlayer 7005 * else set flag for later call to ExitMoviePlayer. 7006 * 7007 * Results: 7008 * None. 7009 * 7010 * Side effects: 7011 * Invokes ExitMoviePlayer or sets flag to schedule this. 7012 * 7013 *---------------------------------------------------------------------- 7014 */ 7015 7016static void 7017MovieExitProc( ClientData clientData ) 7018{ 7019 QTTclDebugPrintf( NULL, 2, "MovieExitProc" ); 7020 7021 gExitState = kQTTclExitStateExitHandlerCalled; 7022 if (gMovieRefCount <= 0) { 7023 ExitMoviePlayer( clientData ); 7024 } 7025} 7026 7027/* 7028 *---------------------------------------------------------------------- 7029 * 7030 * ExitMoviePlayer -- 7031 * 7032 * Last bit of cleanup. 7033 * 7034 * Results: 7035 * None. 7036 * 7037 * Side effects: 7038 * Exits movie toolbox, probably frees memory. 7039 * 7040 *---------------------------------------------------------------------- 7041 */ 7042 7043static void 7044ExitMoviePlayer( ClientData clientData ) 7045{ 7046 QTTclDebugPrintf( NULL, 2, "ExitMoviePlayer" ); 7047 7048 if (gExitState == kQTTclExitStateExitHandlerCalled) { 7049 gExitState = kQTTclExitStateAllFreed; 7050 ExitMovies(); 7051 7052#ifdef _WIN32 7053 TerminateQTML(); /* This used to crash Windows when exit 7054 * when this call came before DestroyNotify */ 7055 TerminateQTVR(); 7056#endif 7057 7058 ExportComponentSettingsFree(); 7059 UserDataHashTablesFree(); 7060 EffectsFree(); 7061 TracksCommandFree(); 7062 } 7063} 7064 7065/* 7066 *---------------------------------------------------------------------- 7067 * 7068 * ProcessSpriteSubcmd -- 7069 * 7070 * Process the "sprite" subcommand. 7071 * 7072 * Results: 7073 * Normal TCL results 7074 * 7075 * Side effects: 7076 * Depends on event. 7077 * 7078 *---------------------------------------------------------------------- 7079 */ 7080 7081static int 7082ProcessSpriteSubcmd( ClientData clientData, 7083 Tcl_Interp *interp, 7084 int objc, 7085 Tcl_Obj *CONST objv[]) 7086{ 7087 int result = TCL_ERROR; 7088 7089 Tcl_SetObjResult( interp, Tcl_NewStringObj( 7090 "sprite subcommand not implimented, yet", -1 ) ); 7091 return result; 7092} 7093 7094/* 7095 *---------------------------------------------------------------------- 7096 * 7097 * ProcessVectorSubcmd -- 7098 * 7099 * Process the "vector" subcommand. 7100 * 7101 * Results: 7102 * Normal TCL results 7103 * 7104 * Side effects: 7105 * Depends on event. 7106 * 7107 *---------------------------------------------------------------------- 7108 */ 7109 7110static int 7111ProcessVectorSubcmd( ClientData clientData, 7112 Tcl_Interp *interp, 7113 int objc, 7114 Tcl_Obj *CONST objv[]) 7115{ 7116 int result = TCL_ERROR; 7117 7118 Tcl_SetObjResult( interp, Tcl_NewStringObj( 7119 "vector subcommand not implimented, yet", -1 ) ); 7120 return result; 7121 7122} 7123 7124static void 7125InstallExtendedSCCallbackProcedures( ComponentInstance ci, long refCon ) 7126{ 7127 SCExtendedProcs procStruct; 7128 7129 procStruct.filterProc = NewSCModalFilterUPP( MySCFilterDialogProc ); 7130 procStruct.hookProc = NULL; 7131 procStruct.customName[0] = 0; 7132 procStruct.refcon = refCon; 7133 SCSetInfo( ci, scExtendedProcsType, &procStruct ); 7134} 7135 7136#if TARGET_OS_MAC && !TARGET_API_MAC_CARBON 7137 7138static pascal Boolean 7139MySCFilterDialogProc( DialogPtr dialogPtr, EventRecord * event, short *itemHit, 7140 long refCon ) 7141{ 7142 Boolean handled = false; 7143 WindowRef eventWindow = NULL; 7144 WindowRef dialogWindow = NULL; 7145 7146#if TARGET_API_MAC_CARBON 7147 dialogWindow = GetDialogWindow( dialogPtr ); 7148#else 7149 dialogWindow = dialogPtr; 7150#endif 7151 7152 switch (event->what) { 7153 7154 case updateEvt: 7155 eventWindow = (WindowRef) event->message; 7156 if ((eventWindow != NULL) && (eventWindow != dialogWindow)) { 7157 7158 /* 7159 * Handle update events to background windows here. 7160 * First, translate mac event to a number of tcl events. 7161 * If any tcl events generated, execute them until empty, and don't wait. 7162 */ 7163 7164 if (TkMacConvertEvent( event )) { 7165 while ( Tcl_DoOneEvent( TCL_IDLE_EVENTS | TCL_DONT_WAIT | TCL_WINDOW_EVENTS ) ) 7166 /* empty */ 7167 ; 7168 } 7169 } 7170 break; 7171 } 7172 return handled; 7173} 7174 7175#endif // TARGET_OS_MAC && !TARGET_API_MAC_CARBON 7176 7177#if TARGET_API_MAC_CARBON 7178static Boolean 7179MySCFilterDialogProc( DialogPtr dialogPtr, EventRecord * event, short *itemHit, 7180 long refCon ) 7181{ 7182 Boolean handled = false; 7183 7184 return handled; 7185} 7186#endif // TARGET_API_MAC_CARBON 7187 7188#ifdef _WIN32 7189Boolean 7190MySCFilterDialogProc( DialogPtr dialogPtr, EventRecord * event, short *itemHit, 7191 long refCon ) 7192{ 7193 Boolean handled = false; 7194 7195 return handled; 7196} 7197#endif // _WIN32 7198 7199/*----------------------------------------------------------------------*/ 7200