Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
main.c
/* |
* File: main.c of SimpleHIMovieViewPlayer |
* |
* Contains: Carbon application demonstrating how to use HIMovieView to play movies |
* |
* Version: 1.0 |
* |
* Created: 05/20/2005 |
* |
* Copyright: Copyright © 2005 Apple Computer, All Rights Reserved |
* |
* Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in |
* consideration of your agreement to the following terms, and your use, installation, modification |
* or redistribution of this Apple software constitutes acceptance of these terms. If you do |
* not agree with these terms, please do not use, install, modify or redistribute this Apple |
* software. |
* |
* In consideration of your agreement to abide by the following terms, and subject to these terms, |
* Apple grants you a personal, non-exclusive license, under Apple's copyrights in this |
* original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the |
* Apple Software, with or without modifications, in source and/or binary forms; provided that if you |
* redistribute the Apple Software in its entirety and without modifications, you must retain this |
* notice and the following text and disclaimers in all such redistributions of the Apple Software. |
* Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to |
* endorse or promote products derived from the Apple Software without specific prior written |
* permission from Apple. Except as expressly stated in this notice, no other rights or |
* licenses, express or implied, are granted by Apple herein, including but not limited to any |
* patent rights that may be infringed by your derivative works or by other works in which the |
* Apple Software may be incorporated. |
* |
* The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR |
* IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY |
* AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE |
* OR IN COMBINATION WITH YOUR PRODUCTS. |
* |
* IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, |
* REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER |
* UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN |
* IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* |
* <1> 05/20/05 QT engineering / dts initial release |
*/ |
#include <Carbon/Carbon.h> |
#include <QuickTime/QuickTime.h> |
#define DEBUG_ERRORS 1 |
#if DEBUG_ERRORS |
#undef require_noerr |
#define require_noerr(err, label) \ |
if (err != noErr) \ |
{ \ |
printf("Error: %s[%i]\n", __FILE__, __LINE__); \ |
fflush(stdout); \ |
assert(err == noErr); \ |
goto label; \ |
} |
#endif |
// ID's set up in IB |
HIViewID kHIMovieViewID = {'moov', 0}; |
HIViewID kOptimalSizeID = {'moov', 5}; |
HIViewID kControllerSizeID = {'moov', 6}; |
// command IDs |
enum { |
kHICommandControllerVisible = 'VIZZ', |
kHICommandAcceptsFocus = 'AFOC', |
kHICommandEditable = 'EDIT', |
kHICommandHandleEditingUI = 'HEUI', |
}; |
// our data |
typedef struct MainWindowData { |
WindowRef window; |
NavDialogRef openDialog; |
Movie movie; |
MovieController movieController; |
HIViewRef view; |
} MainWindowData, *MainWindowPtr; |
// quit application on window closing |
static OSStatus MainWindowClosed(EventRef event, MainWindowData *inWindowData) |
{ |
QuitApplicationEventLoop(); |
return noErr; |
} |
// MainWindowResizeToMovie is called from the controll event handler to resize |
// the window when the HIMovieView's Optimal Bounds have changed |
static OSStatus MainWindowResizeToMovie(MainWindowData *inWindowData) |
{ |
OSStatus err = noErr; |
HIRect viewBounds; |
HIRect optimalBounds; |
HIPoint minLimits; |
Rect windowBounds; |
EventRef event; |
CFStringRef text; |
if (NULL == inWindowData->movie) return err; |
// get the HIView's current bounds |
err = HIViewGetBounds(inWindowData->view, &viewBounds); |
require_noerr(err, bail); |
// to get the HIView's optimal bounds we create a carbon event and send it to the view |
err = CreateEvent(NULL, kEventClassControl, kEventControlGetOptimalBounds, GetCurrentEventTime(), kEventAttributeUserEvent, &event); |
require_noerr(err, bail); |
err = SendEventToEventTargetWithOptions(event, HIObjectGetEventTarget((HIObjectRef)inWindowData->view), kEventTargetDontPropagate); |
require_noerr(err, bail); |
err = GetEventParameter(event, kEventParamControlOptimalBounds, typeHIRect, NULL, sizeof(HIRect), NULL, &optimalBounds); |
require_noerr(err, bail); |
ReleaseEvent(event); |
// we do the same to get window's minimum bounds |
err = CreateEvent(NULL, kEventClassWindow, kEventWindowGetMinimumSize, GetCurrentEventTime(), kEventAttributeUserEvent, &event); |
require_noerr(err, bail); |
err = SendEventToEventTargetWithOptions(event, GetWindowEventTarget(inWindowData->window), kEventTargetDontPropagate); |
require_noerr(err, bail); |
err = GetEventParameter(event, kEventParamDimensions, typeHIPoint, NULL, sizeof(HIPoint), NULL, &minLimits); |
require_noerr(err, bail); |
// update the text that displays the HIMovieView's optimal bounds |
text = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d x %d"), (UInt32)optimalBounds.size.width, (UInt32)optimalBounds.size.height); |
if (NULL != text) { |
HIViewRef control; |
HIViewFindByID(HIViewGetRoot(inWindowData->window), kOptimalSizeID, &control); |
HIViewSetText(control, text); |
CFRelease(text); |
} |
// grow window bounds by the difference |
err = GetWindowBounds(inWindowData->window, kWindowContentRgn, &windowBounds); |
require_noerr(err, bail); |
windowBounds.right += (short)(optimalBounds.size.width - viewBounds.size.width); |
windowBounds.bottom += (short)(optimalBounds.size.height - viewBounds.size.height); |
// but make sure and limit it to the minimum size of the window |
if ((windowBounds.right - windowBounds.left) < minLimits.x) windowBounds.right = minLimits.x + windowBounds.left; |
if ((windowBounds.bottom - windowBounds.top) < minLimits.y) windowBounds.bottom = minLimits.y + windowBounds.top; |
err = SetWindowBounds(inWindowData->window, kWindowContentRgn, &windowBounds); |
require_noerr(err, bail); |
bail: |
if (event != NULL) |
ReleaseEvent(event); |
return err; |
} |
// get the movie and set it on the HIMovieView |
static void MainWindowNavOpen(NavCBRecPtr params, MainWindowData *inWindowData) |
{ |
OSStatus err; |
NavReplyRecord reply; |
AEDesc descriptor; |
FSRef file; |
DataReferenceRecord dataRef = {0}; |
QTVisualContextRef visualContext = NULL; |
Boolean active = TRUE; |
Movie oldMovie = NULL; |
// create an array of properties for NewMovieFromProperties |
// these properties describe how to create the new movie |
// see Movies.h for the full list of availale properties |
QTNewMoviePropertyElement newMovieProperties[] = { |
{kQTPropertyClass_DataLocation, kQTDataLocationPropertyID_DataReference, sizeof(dataRef), &dataRef, 0}, |
{kQTPropertyClass_NewMovieProperty, kQTNewMoviePropertyID_Active, sizeof(active), &active, 0}, |
{kQTPropertyClass_Context, kQTContextPropertyID_VisualContext, sizeof(visualContext), &visualContext, 0}, |
}; |
// get the FSRef from Navigation Services |
err = NavDialogGetReply(params->context, &reply); |
require_noerr(err, bail); |
err = AECoerceDesc(&reply.selection, typeFSRef, &descriptor); |
NavDisposeReply(&reply); |
require_noerr(err, bail); |
err = AEGetDescData(&descriptor, &file, sizeof(FSRef)); |
AEDisposeDesc(&descriptor); |
require_noerr(err, bail); |
// create a QuickTime data reference from the FSRef |
err = QTNewDataReferenceFromFSRef(&file, 0, &dataRef.dataRef, &dataRef.dataRefType); |
require_noerr(err, bail); |
// if there's an old movie save it so we can dispose of it if |
// we load up a new movie successfully |
oldMovie = inWindowData->movie; |
inWindowData->movie = NULL; |
// create a new movie using movie properties |
// when calling this function, you supply a set of input properties that describe the information |
// required to instantiate the movie (its data reference, audio context, visual context, and so on) |
err = NewMovieFromProperties(sizeof(newMovieProperties) / sizeof(newMovieProperties[0]), // the number of properties in the array passed in inputProperties |
newMovieProperties, // a pointer to a property array describing how to instantiate the movie |
0, // number of properties in the array passed in outputProperties |
NULL, // pointer to a property array to receive output parameters - NULL if you donÕt want this information |
&inWindowData->movie); // pointer to a variable that receives the new movie |
// make sure to dispose of the dataRef we no longer need it |
DisposeHandle(dataRef.dataRef); |
require_noerr(err, bail); |
// set the HIMovieView's current movie |
err = HIMovieViewSetMovie(inWindowData->view, inWindowData->movie); |
require_noerr(err, bail); |
if (oldMovie != NULL) |
DisposeMovie(oldMovie); |
bail: |
if (err != noErr && inWindowData->movie != NULL) { |
DisposeMovie(inWindowData->movie); |
inWindowData->movie = NULL; |
} |
} |
// Navigation services callback to handle the sheet |
static void MainWindowNavEventProc(NavEventCallbackMessage message, NavCBRecPtr params, MainWindowData *inWindowData) |
{ |
switch (message) { |
case kNavCBUserAction: |
if (params->userAction == kNavUserActionOpen) |
MainWindowNavOpen(params, inWindowData); |
break; |
case kNavCBTerminate: |
NavDialogDispose(inWindowData->openDialog); |
inWindowData->openDialog = NULL; |
EnableMenuCommand(NULL, kHICommandOpen); |
break; |
default: |
break; |
} |
} |
// MainWindowOpenMovie is called from the Carbon Command handler when a user wants to open a file |
static OSStatus MainWindowOpenMovie(MainWindowData *inWindowData) |
{ |
OSStatus err = noErr; |
NavDialogCreationOptions options; |
DisableMenuCommand(NULL, kHICommandOpen); |
err = NavGetDefaultDialogCreationOptions(&options); |
require_noerr(err, bail); |
options.modality = kWindowModalityWindowModal; |
options.parentWindow = inWindowData->window; |
err = NavCreateGetFileDialog(&options, NULL, (NavEventUPP)&MainWindowNavEventProc, NULL, NULL, inWindowData, &inWindowData->openDialog); |
require_noerr(err, bail); |
err = NavDialogRun(inWindowData->openDialog); |
if (err == userCanceledErr) err = noErr; |
bail: |
return err; |
} |
// MainWindowCommandUpdateStatus is used for taking care of enabling or disabling menu items |
// we only care about the edit menu in this sample |
static OSStatus MainWindowCommandUpdateStatus(EventRef event, MainWindowData *inWindowData) |
{ |
HICommand aCommand; |
GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &aCommand); |
// the HIMovieView can handle the edit menu for us when it has the editing, editingUI and accepts focus |
// attributes set -- when they're off we need to disable the menu items ourselves |
switch (aCommand.commandID) { |
case kHICommandUndo: |
case kHICommandCut: |
case kHICommandCopy: |
case kHICommandPaste: |
case kHICommandClear: |
case kHICommandSelectAll: |
{ |
DisableMenuItem(aCommand.menu.menuRef, aCommand.menu.menuItemIndex); |
} |
} |
return eventNotHandledErr; |
} |
// MainWindowCommandProcess Carbon event handler takes care of menu item selections and |
// check box status updating the HIMovieView's attributes as needed |
static OSStatus MainWindowCommandProcess(EventRef event, MainWindowData *inWindowData) |
{ |
OSStatus err; |
HICommandExtended command; |
err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommandExtended), NULL, &command); |
require_noerr(err, bail); |
err = eventNotHandledErr; |
switch (command.commandID) { |
case kHICommandOpen: |
// open a movie file |
err = MainWindowOpenMovie(inWindowData); |
break; |
// take care of the checkboxes |
case kHICommandControllerVisible: |
{ |
// change the attribute controlling the visibility of the QuickTime Movie Controller in the HIMovieView |
SInt16 value = GetControlValue(command.source.control); |
if (value) { |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewControllerVisibleAttribute, kHIMovieViewNoAttributes); |
} else { |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewNoAttributes, kHIMovieViewControllerVisibleAttribute); |
} |
break; |
} |
case kHICommandAcceptsFocus: |
{ |
// change the attribute controlling HIMovieView user focus |
// for editing to work HIMovieView must have focus |
SInt16 value = GetControlValue(command.source.control); |
if (value) { |
ControlRef control; |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewAcceptsFocusAttribute, kHIMovieViewNoAttributes); |
// if we're not already focused do it now |
GetKeyboardFocus(inWindowData->window, &control); |
if (control != inWindowData->view) { |
SetKeyboardFocus(inWindowData->window, inWindowData->view, kControlFocusNextPart); |
} |
} else { |
// clear it |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewNoAttributes, kHIMovieViewAcceptsFocusAttribute); |
ClearKeyboardFocus(inWindowData->window); |
} |
break; |
} |
case kHICommandEditable: |
{ |
// change the attribute controlling the ability for HIMovieView to edit the movie being displayed |
SInt16 value = GetControlValue(command.source.control); |
if (value) { |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewEditableAttribute, kHIMovieViewNoAttributes); |
} else { |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewNoAttributes, kHIMovieViewEditableAttribute); |
} |
break; |
} |
case kHICommandHandleEditingUI: |
{ |
// change the attribute controlling the ability for HIMovieView to controll the Edit Menu user interface |
// for this to work, HIMovieView must be editable and have focus |
SInt16 value = GetControlValue(command.source.control); |
if (value) { |
HIMovieViewChangeAttributes(inWindowData->view, kHIMovieViewHandleEditingHIAttribute, 0); |
} else { |
HIMovieViewChangeAttributes(inWindowData->view, 0, kHIMovieViewHandleEditingHIAttribute); |
} |
break; |
} |
default: |
break; |
} |
bail: |
return err; |
} |
// MainWindowEventHandler is our standard Carbon event handler |
static pascal OSStatus MainWindowEventHandler(EventHandlerCallRef call, EventRef event, void* inUserData ) |
{ |
UInt32 eventClass = GetEventClass(event); |
UInt32 eventKind = GetEventKind(event); |
OSStatus err = eventNotHandledErr; |
MainWindowData *data = (MainWindowData*)inUserData; |
require(NULL != data, bail); |
switch (eventClass) { |
// handle window events |
case kEventClassWindow: |
switch (eventKind) { |
case kEventWindowBoundsChanged: |
{ |
HIRect viewBounds; |
CFStringRef text; |
// get view's current bounds |
HIViewGetBounds(data->view, &viewBounds); |
// update the text that displays the Windows current bounds |
text = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d x %d"), (UInt32)viewBounds.size.width, (UInt32)viewBounds.size.height); |
if (NULL != text) { |
HIViewRef control; |
HIViewFindByID(HIViewGetRoot(data->window), kControllerSizeID, &control); |
HIViewSetText(control, text); |
CFRelease(text); |
} |
break; |
} |
// return the minimum size we want the window to be able to resize to |
case kEventWindowGetMinimumSize: |
{ |
HISize controllerSize; |
HIPoint dimensions = { 498, 272 }; |
controllerSize = HIMovieViewGetControllerBarSize(data->view); |
dimensions.y += controllerSize.height; |
SetEventParameter(event, kEventParamDimensions, typeHIPoint, sizeof(HIPoint), &dimensions); |
err = noErr; |
break; |
} |
case kEventWindowClosed: |
err = MainWindowClosed(event, data); |
break; |
default: |
break; |
} // switch |
break; |
// handle commands |
case kEventClassCommand: |
switch (eventKind) { |
case kEventCommandUpdateStatus: |
err = MainWindowCommandUpdateStatus(event, data); |
break; |
case kEventCommandProcess: |
err = MainWindowCommandProcess(event, data); |
break; |
default: |
break; |
} // switch |
break; |
default: |
break; |
} |
bail: |
return err; |
} |
// MovieViewEventHandler handles HIMovieView events |
static pascal OSStatus MovieViewEventHandler(EventHandlerCallRef call, EventRef event, void* inUserData) |
{ |
OSStatus err = eventNotHandledErr; |
UInt32 eventClass = GetEventClass(event); |
UInt32 eventKind = GetEventKind(event); |
MainWindowData *data = (MainWindowData*)inUserData; |
switch (eventClass) { |
case kEventClassMovieView: |
switch (eventKind) { |
// the optimal bounds of the HIMovieView has changed so resize the window appropriately |
case kEventMovieViewOptimalBoundsChanged: |
err = MainWindowResizeToMovie(data); |
break; |
default: |
break; |
} // switch |
break; |
default: |
break; |
} |
return err; |
} |
int main(int argc, char* argv[]) |
{ |
OSStatus err = noErr; |
IBNibRef nib = NULL; |
EventRef event; |
HICommandExtended command = {0, kHICommandOpen}; |
EventTypeSpec windowEvents[] = {{kEventClassWindow, kEventWindowClosed}, |
{kEventClassWindow, kEventWindowBoundsChanged}, |
{kEventClassWindow, kEventWindowGetMinimumSize}, |
{kEventClassCommand, kEventCommandUpdateStatus}, |
{kEventClassCommand, kEventCommandProcess}}; |
EventTypeSpec viewEvents[] ={{kEventClassMovieView, kEventMovieViewOptimalBoundsChanged}}; |
MainWindowData windowData = { 0 }; |
EnterMovies(); |
// standard stuff to create a window |
err = CreateNibReference(CFSTR("main"), &nib); |
require_noerr(err, CantOpenNib); |
err = SetMenuBarFromNib(nib, CFSTR("MenuBar")); |
require_noerr(err, bail); |
err = CreateWindowFromNib(nib, CFSTR("MainWindow"), &windowData.window); |
require_noerr(err, bail); |
// grab the movie view from the view hierarchy |
err = HIViewFindByID(HIViewGetRoot(windowData.window), kHIMovieViewID, &windowData.view); |
require_noerr(err, bail); |
// install event handlers |
err = InstallWindowEventHandler(windowData.window, &MainWindowEventHandler, GetEventTypeCount(windowEvents), windowEvents, &windowData, NULL); |
require_noerr(err, bail); |
err = InstallHIObjectEventHandler((HIObjectRef)windowData.view, &MovieViewEventHandler, GetEventTypeCount(viewEvents), viewEvents, &windowData, NULL); |
require_noerr(err, bail); |
// dispose the NIB ref, we don't need it anymore |
DisposeNibReference(nib); |
nib = NULL; |
// set inital movie view attributes and show the window |
OptionBits setAttributes = kHIMovieViewAutoIdlingAttribute | kHIMovieViewControllerVisibleAttribute; |
OptionBits clearAttributes = kHIMovieViewEditableAttribute | kHIMovieViewHandleEditingHIAttribute | kHIMovieViewAcceptsFocusAttribute; |
err = HIMovieViewChangeAttributes(windowData.view, setAttributes, clearAttributes); |
require_noerr(err, bail); |
ShowWindow(windowData.window); |
// send an open event to ourselves to bring down the Navigation sheet and grab a movie |
err = CreateEvent(NULL, kEventClassCommand, kEventCommandProcess, GetCurrentEventTime(), kEventAttributeUserEvent, &event); |
require_noerr(err, bail); |
err = SetEventParameter(event, kEventParamDirectObject, typeHICommand, sizeof(HICommandExtended), &command); |
require_noerr(err, bail); |
err = SendEventToEventTargetWithOptions(event, GetWindowEventTarget(windowData.window), kEventTargetDontPropagate); |
require_noerr(err, bail); |
ReleaseEvent(event); |
// go... |
RunApplicationEventLoop(); |
bail: |
if (nib != NULL) |
DisposeNibReference(nib); |
CantOpenNib: |
ExitMovies(); |
return err; |
} |
Copyright © 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-07-15