TweetFollow Us on Twitter

Studio 54

Volume Number: 19 (2003)
Issue Number: 7
Column Tag: QuickTime

QuickTime Toolkit

Studio 54

by Tom Monroe

Developing QuickTime Applications with AppleScript Studio

Introduction

In the previous QuickTime Toolkit article, we started building a QuickTime-savvy application using AppleScript Studio. In this article we'll finish up.

Setting Up the Menus

Let's turn to ScripTeez' menus. The Application menu is the easiest to configure, since we simply need to change the name of the application to "ScripTeez" in four instances, as shown in Figure 13. I've also set the keyboard shortcut for the "Hide Others" item to be Command-Option-H, as dictated by the Aqua Human Interface Guidelines.


Figure 13: The Application menu nib

In the Edit menu, we need to remove the items that don't apply to movies (the Find and Spelling menu items) and add the "Select None" item, as shown in Figure 14.


Figure 14: The Edit menu nib

All these items are handled automatically by Cocoa (and in particular, by the NSMovieView instance in our movie window), except for the one we just added. In this case, we need to attach an AppleScript event handler. As before, select the "AppleScript" panel in the Info window and then check the "choose menu item" and "update menu item" handlers, as in Figure 15. Skeletal handlers are automatically added to the specified script file (that is, ScripTeez.applescript); we'll add code to those handlers later.


Figure 15: The Select None menu event handlers

Let's add one more menu to ScripTeez, a Movie menu that allows us to select a looping mode for the movie in the movie window. Figure 16 shows the updated main menu nib.


Figure 16: The Movie menu nib

As you'd guess, we need to attach AppleScript handlers to adjust and handle these menu items. Figure 17 shows the Info window for the third item in the Movie menu, the "Palindrome Looping" item. Notice that the name of the item is "palindromeLooping".


Figure 17: The Palindrome Looping menu event handlers

Adjusting the Project Settings

Before we launch into writing code to handle these events, we need to make a couple of final adjustments to our project. We need to add the QuickTime framework to the project, and we need to specify the kinds of files that our application can open.

To add the QuickTime framework, simply select "Add Frameworks..." in Project Builder's Project menu and then choose the file "QuickTime.framework". It will be added to the list of linked frameworks.

To specify the kinds of files our application can open and hence what kinds of files should be selectable in the file-opening dialog box (displayed at application launch time), select the "Edit Active Target" item in the Project menu. Click the "Document Types" item on the left-hand side and add the desired document types. Figure 18 shows our document types settings. We want ScripTeez to be able to open QuickTime movie files and Flash files.


Figure 18: The openable file types

AppleScript Studio Movie Classes

Now it's time to write some code to load a movie from a movie file and to handle the menu items we've added to the default menu bar. Recall that the only thing we added to the default empty application window was a view of type NSMovieView, which we named "movieView". This name allows us to target AppleScript actions at that movie view. For instance, in the awake-from-nib handler, we might set a local variable theMovieView to point to that view like this:

set theMovieView to the movie view "movieView" of theObject

(Recall that the awake-from-nib handler is passed the object that's being awakened; in this case, it's the movie window.)

But what vocabulary can we use to manipulate the movie view? To find this out, we can double-click the item labeled "AppleScriptKit.asdictionary" in the project window (see Figure 4 again). Expand the item labeled "Control View Suite" in the left-hand column, and then expand the Classes item. We'll see a couple dozen view types, including "movie view". If we click on "movie view", we'll see the list of properties shown in Figure 19.


Figure 19: The movie view properties

This list shows us the built-in properties of movie views currently supported by AppleScript Studio. For instance, we can get and set the movie volume, the looping state, and the playback rate. We can get (but not set) the movie controller identifier. We can also get and set the movie associated with the movie view. So, we might set the movie to palindrome looping like this:

set the loop mode of theMovieView to -
                              looping back and forth playback

(The character "-"is AppleScript's line continuation character; we can insert it into a script by typing Option-L; this allows very long statements to occupy several lines in our script files.)

Loading a Movie from a File

ScripTeez, you'll recall, supports only one movie window. We'll display the standard file-opening dialog box at application launch time, to elicit a movie file from the user. We can display that dialog box and get the full pathname of the selected file with this simple command:

set theMoviePath to choose file

Then we can assign the movie in that file to the movie view like this:

set the movie of theMovieView to load movie theMoviePath

Setting the Size of a Movie Window

If you look back at Figure 7, you'll see that the "Visible at launch time" check box in the list of movie window attributes is unselected; this is because we don't want the movie window to be visible while the file-opening dialog is displayed. It's also because, before we display the movie window to the user, we want to adjust the size of the movie window to exactly contain the movie at its natural size and the 20-pixel border on all sides of the movie view.

The only problem is that AppleScript Studio does not (as far as I can determine) include any built-in method for getting the natural size of a movie. The movie rect property returns the current size of the movie rectangle, which will just be the size of the movie view as contained in the nib file once we've assigned the movie to the movie view. Fortunately, AppleScript Studio supports an easy way to call code written in other languages, using the call method command. In ScripTeez, we'll need to use this command twice, first to get the natural size of a movie and second to handle the "Select None" menu item.

Let's look at the menu-handling task first, since it's somewhat simpler than the movie-sizing task. When the user chooses the "Select None" menu item, we'll execute this line of script:

call method "selectNone:" with parameter theMovieView

This call method command tells AppleScript Studio to look for an Objective-C method named "selectNone:" and to call it, passing as its single argument the value of the variable theMovieView.

When we issue the call method command, we can specify the class whose method is to be called. For simplicity, however, we'll implement the selectNone: method (and the movieWindowContentRect: method, which we'll encounter in a moment) as categories on the NSApplication class.

To begin, let's add two new files to the ScripTeez project; let's call them ScrTzMethods.m and ScrTzMethods.h. Listing 10 shows the file ScrTzMethods.h.

Listing 10: Declaring a category on NSApplication

ScrTzMethods.h

@interface NSApplication (ScrTzMethods)

- (NSRect)movieWindowContentRect:(NSMovieView *)movieView;
- (void)selectNone:(NSMovieView *)movieView;

@end

The file ScrTzMethods.m contains the actual implementation of the ScrTzMethods category. Listing 11 shows our definition of the selectNone: method.

Listing 11: Selecting none of a movie

selectNone

- (void)selectNone:(NSMovieView *)movieView
{ 
   MovieController mc = NULL;
   TimeRecord tr;
   mc = (MovieController)[movieView movieController];
   if (mc != NULL) {
      tr.value.hi = 0;
      tr.value.lo = 0;   
      tr.base = 0;
      tr.scale = GetMovieTimeScale(
                                       [[movieView movie] QTMovie]);   
      MCDoAction(mc, mcActionSetSelectionDuration, &tr);
   }
}

This is easy stuff that we've seen before. We retrieve the movie controller identifier from the movie view object, fill out a time record appropriately, and then call MCDoAction with the mcActionSetSelectionDuration action. Notice that we do not return a value to our caller.

Listing 12 shows our implementation of the movieWindowContentRect: method. As with selectNone:, it takes the movie view as the single input parameter. We retrieve the movie and movie controller identifiers, call GetMovieNaturalBoundsRect to get the natural size of the movie, and then adjust the rectangle to contain the movie controller bar (if it's visible) and the 20-pixel border on all sides of the movie view. The rectangle we pass back to the caller contains the desired size of the entire content region of the movie window.

Listing 12: Getting a movie window's size

movieWindowContentRect

- (NSRect)movieWindowContentRect:(NSMovieView *)movieView
{
   Rect rect = {0, 0, 0, 0};
   Movie movie = NULL;
   MovieController mc = NULL;
   movie = (Movie)[[movieView movie] QTMovie];
   mc = (MovieController)[movieView movieController];
   if (movie != NULL)
      GetMovieNaturalBoundsRect(movie, &rect);
   if (MCGetVisible(mc) == 1)
      rect.bottom += kControllerBarHeight;
   return NSMakeRect(0, 0, 
      (rect.right - rect.left) + (2 * kMovieWindowBorder), 
      (rect.bottom - rect.top) + (2 * kMovieWindowBorder));
}

What does our AppleScript call to movieWindowContentRect: look like? As with selectNone:, we want to pass the movie view theMovieView as a parameter. The key difference is that we need to capture the result of the method call, which we can do by copying that result to a local list of values, like this:

copy (call method "movieWindowContentRect:" -
      with parameter theMovieView) to -
      {theIgnoreLeft, theIgnoreTop, theMovieWindWid, -
                                                      theMovieWindHgt}

We are interested only in the third and fourth items in the NSRect structure, which are the desired width and height of the movie window content region. Once we've got those values, we can determine the size and location of the movie window fairly easily. Listing 13 shows our complete calculation here.

Listing 13: Setting a movie window's size

on awake from nib

set theTitleBarHgt to 20
copy (call method "movieWindowContentRect:" -
      with parameter theMovieView) to -
      {theIgnoreLeft, theIgnoreTop, theMovieWindWid, -
                                                      theMovieWindHgt}
copy the bounds of the theWindow to -
      {theWindLeft, theWindBottom, theWindRight, theWindTop}
set the bounds of the theWindow to -
      {theWindLeft, theWindTop - (theMovieWindHgt + - 
         theTitleBarHgt), theWindLeft + theMovieWindWid, - 
                                                      theWindTop}

Setting the Title of a Movie Window

One task remains to be performed in the awake-from-nib event handler; we need to set the title of the movie window to the basename of the movie's pathname. (The basename is the portion of the pathname that follows the rightmost path separator.) These three lines of AppleScript will do the job:

set the text item delimiters to ":"
set theFileName to (theMoviePath as string)
set the title of the theWindow to - 
               the last word of theFileName

We can now make the window visible:

show the window of theMovieView

Movie Playback

At this point, the user has selected a movie file using the file-opening dialog box; we've loaded the movie in that file into the movie view in the movie window and adjusted the initial size of the movie window as appropriate to display the movie at its natural size. AppleScript Studio, in concert with the relevant Cocoa classes, handles all subsequent user actions like moving or minimizing the window, starting and stopping the movie, editing the movie, and so forth. With very little AppleScript code indeed, and with just a small detour into Objective-C, we've got a fully-functioning movie playback application.

We need to intercede here only to handle the menu items that we added to ScripTeez, namely the "Select None" item and the three looping state items in the Movie menu.

Manipulating a Movie's Looping State

As we saw earlier, a menu item can have two handlers associated with it, one that's called when the state of the menu needs to be adjusted (or "updated") and one that's called when the menu item is actually selected. The update handler is called before the menu item is displayed to the user; typically this occurs when the user clicks somewhere in the menu bar. Listing 14 shows the complete update handler for our custom menu items.

Listing 14: Adjusting the menus

on update menu item

on update menu item theObject
   set theMovieView to movie view "movieView" of -
                                                            front window
   set theLoopMode to loop mode of theMovieView
   
   set enableItem to 1
   set checkItem to 0
   
   if name of theObject is "selectNone" then
      if editable of theMovieView is equal to true then -
                                             set enableItem to 1
   else if name of theObject is "noLooping" then
      if theLoopMode is equal to normal playback then -
                                             set checkItem to 1
      set state of theObject to checkItem
   else if name of theObject is "normalLooping" then -
      if theLoopMode is equal to looping playback then -
                                             set checkItem to 1
      set state of theObject to checkItem
   else if name of theObject is "palindromeLooping" then -
      if theLoopMode is equal to -
            looping back and forth playback then -
                                             set checkItem to 1
      set state of theObject to checkItem
   else
      set enableItem to 0
   end if
   
   return enableItem
end update menu item

Notice that we enable the "Select None" menu item only if the movie is listed as editable. Also, we set the state property of the looping menu items so that a check mark is displayed in the currently-active looping state item.

Handling the selection of one of our custom menu items is even easier than adjusting the menu items. We've already seen that we need to use the call method command to handle the "Select None" item. We can handle the looping menu items with pure AppleScript, as shown in Listing 15.

Listing 15: Handling menu item selections

on choose menu item

on choose menu item theObject
   set theWindow to front window
   set theMovieView to movie view "movieView" of theWindow
   
   if name of theObject is "selectNone" then
      call method "selectNone:" with parameter theMovieView
   else if name of theObject is "noLooping" then
      set loop mode of theMovieView to normal playback
   else if name of theObject is "normalLooping" then
      set loop mode of theMovieView to looping playback
   else if name of theObject is "palindromeLooping" then
      set loop mode of theMovieView to -
                                       looping back and forth playback
   end if
end choose menu item

Closing a Movie Window

When the user quits ScripTeez, the movie window will close automatically. In an ideal world, we would first look to see whether the movie in the window had been edited and then prompt the user to save or discard any changes. To my knowledge, however, AppleScript does not provide any easy way to update the movie data in a movie file. So we'd need to use the call method command once again to call out to Objective-C methods. I'll leave that as an exercise for the interested reader.

ScripTeez does not provide any way to open a new movie window if we happen to close the movie window that's opened at application launch time. Accordingly, we should probably set things up so that closing the movie window will cause ScripTeez to exit. Listing 16 shows the will-close method of the movie window.

Listing 16: Closing a movie window

on will close

on will close theObject
   quit
end will close

Conclusion

AppleScript's English-like language makes our code extremely easy to read; I doubt that anyone would have too much trouble understanding even the most complicated scripts we've encountered in this article. We can use AppleScript Studio's built-in commands and properties to handle a good deal of what's required to open and display QuickTime movies. Moreover, if need be, we can supplement our AppleScript with direct calls to Objective-C code to manipulate the Cocoa classes underlying our AppleScript Studio applications. This high-level scriptability and support for low-level method calling make AppleScript Studio an interesting addition to our QuickTime programming toolbox.


Tim Monroe in a member of the QuickTime engineering team. You can contact him at monroe@apple.com. The views expressed here are not necessarily shared by his employer.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adobe InCopy CC 2018 13.0.0.123 - Create...
InCopy CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous InCopy customer). Adobe InCopy CC 2018, ideal for large team projects... Read more
OnyX 3.3.8 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more
Merlin Project 4.3.1 - $289.00
Merlin Project is the leading professional project management software for OS X. If you plan complex projects on your Mac, you won’t get far with a simple list of tasks. Good planning raises... Read more
DiskCatalogMaker 7.2.5 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
WhatsApp 0.2.6426 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Ableton Live 9.7.5 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
Maintenance 2.3.5 - System maintenance u...
Maintenance is a system maintenance and cleaning utility. It allows you to run miscellaneous tasks of system maintenance: Check the status of the hard disk Repair permissions Run periodic scripts... Read more
OnyX 3.3.8 - Maintenance and optimizatio...
OnyX is a multifunction utility that you can use to verify the startup disk and the structure of its system files, to run miscellaneous maintenance and cleaning tasks, to configure parameters in the... Read more
Merlin Project 4.3.1 - $289.00
Merlin Project is the leading professional project management software for OS X. If you plan complex projects on your Mac, you won’t get far with a simple list of tasks. Good planning raises... Read more
WhatsApp 0.2.6426 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more

Guns Royale guide - beginner tips and tr...
If you've been itching to find a mobile battle royale game like Player Unknown's Battlegrounds, you're finally in luck. Guns Royale is a new survival shooter that takes all of the things you love about good ol' PUBG and puts it in a tidy mobile... | Read more »
What we know about Animal Crossing on mo...
At last, we'll be receiving some news about the mobile version of Animal Crossing in a special Nintendo Director at11 PM on October 24. There's been little word on the game since it was first announced, having been met with a series of delays.... | Read more »
Darts of Fury guide - how to rise in the...
Darts of Fury is a new, immensely absorbing darts game from indie studio Yakuto. It's darts in its purest form, but collectible darts and other upgrades give this game an addictive edge that's hard to shake. As your progress out of the beginner... | Read more »
ICEY (Games)
ICEY 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ICEY is a 2D side-scrolling action game. As you follow the narrator's omnipresent voice, you will see through ICEY's eyes and learn the... | Read more »
The best new games we played this week -...
We've made it, folks. Another weekend is upon us. It's time to sit back and relax with the best new releases of the week. Puzzles, strategy RPGs, and arcade games abound this week. There's a lot of quality stuff to unpack this week, so let's hop... | Read more »
Wheels of Aurelia (Games)
Wheels of Aurelia 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: | Read more »
Halcyon 6: Starbase Commander guide - ti...
Halcyon 6 is a well-loved indie RPG with stellar tactical combat and some pretty good writing, too. It's now landed on the App Store, so mobile fans, if you're itching for a good intergalactic adventure, here's your game. Being a strategy RPG, the... | Read more »
Game of Thrones: Conquest guide - how to...
Fans of base building games might be excited to know that yet another entry in the genre has materialized - Game of Thrones: Conquest. Yes, you can now join the many kingdoms of the famed book series, or create your own, as you try to conquer... | Read more »
Halcyon 6: Starbase Commander (Games)
Halcyon 6: Starbase Commander 1.4.2.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.4.2.0 (iTunes) Description: An epic space strategy RPG with base building, deep tactical combat, crew management, alien diplomacy,... | Read more »
Legacy of Discord celebrates its 1 year...
It’s been a thrilling first year for fans of Legacy of Discord, the stunning PvP dungeon-crawling ARPG from YOOZOO Games, and now it’s time to celebrate the game’s first anniversary. The developers are amping up the festivities with some exciting... | Read more »

Price Scanner via MacPrices.net

27″ 3.4GHz iMac on sale for $1699, save $100
Amazon has the 27″ 3.4GHz iMac (MNE92LL/A) on sale today for $1699 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model (except for Apple’s $1529... Read more
Clearance 2016 15″ MacBook Pros available for...
B&H Photo has leftover 2016 15″ MacBook Pros available for up to $700 off original MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: – 15″ 2.7GHz Touch Bar MacBook Pro Space... Read more
Save $100 on 13″ MacBook Airs, prices start a...
Adorama has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. Adorama charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off MSRP... Read more
1.4GHz Mac mini available for $399, $100 off...
TigerDirect has the 1.4GHz Mac mini on sale today for $399 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Although currently out of stock,... Read more
21″ 2.3GHz iMac on sale for $999, save $100
MacMall has the 21″ 2.3GHz iMac (MMQA2LL/A) on sale today for $999 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
12″ iPad Pros on sale for $50 off MSRP, no ta...
Adorama has 12″ iPad Pros on sale today for $50 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: – 12″ 64GB iPad Pro: $749, save $50 – 12″ 256GB iPad Pro: $899, save $50... Read more
9″ iPads on sale for $30 off, starting at $29...
MacMall has 9″ iPads on sale for $30 off including free shipping: – 9″ 32GB iPad: $299 – 9″ 128GB iPad: $399 Read more
Apple restocks full line of refurbished 13″ M...
Apple has restocked a full line of Apple Certified Refurbished 2017 13″ MacBook Pros for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
13″ 3.1GHz/256GB MacBook Pro on sale for $167...
Amazon has the 2017 13″ 3.1GHz/256GB Space Gray MacBook Pro on sale today for $121 off MSRP including free shipping: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (MPXV2LL/A): $1678 $121 off MSRP Keep an... Read more
13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more

Jobs Board

*Apple* Professional Learning Specialist - A...
Job Summary The Apple Professional Learning Specialist is a full-time position with Apple . This position requires a high caliber work ethic built from respect, Read more
*Apple* Professional Learning Specialist - A...
Job Summary The Apple Professional Learning Specialist is a full-time position for one year with Apple in the Kanawha, WV area. This position requires a high Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Project Engineer, *Apple* Education Profess...
Project Engineer, Apple Education Professional Services Job Number: 113143353New York City, New York, United StatesPosted: Oct. 17, 2017Weekly Hours: 40.00 Job Read more
Commerce Software Engineer, *Apple* Media P...
Commerce Software Engineer, Apple Media Products Job Number: 113092072New York City, New York, United StatesPosted: Oct. 19, 2017Weekly Hours: 40.00 Job Summary With Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.