AppleScript QuickTime – Wait Until Movie Recording Window is Active

applescriptmacosquicktimestreaming

I'm trying to resize a Quicktime Movie Recording Window–only after it's active.
Is this possible?
The below script does work––if I hardcode the delay time.
Any help is appreciated.
Thanks

do shell script "open " & quoted form of "/Applications/QuickTime Player.app"

tell application "QuickTime Player"
        activate

        -- Start iPhone Screen cast of Game
        set newMovieRecording to new movie recording

        tell application "System Events"

            -- Wait for Movie Recording Window to Launch
            repeat until (exists window "Movie Recording" of application process "QuickTime Player")
                delay 2
            end repeat

            -- Resize Quicktime Window now that Window is active
            set position of first window of application process "QuickTime Player" to {1087, 497}
            set size of first window of application process "QuickTime Player" to {350, 621}
        end tell
    end tell

Best Answer

I'm trying to resize a Quicktime Movie Recording Window--only after it's active. Is this possible? The below script does work––if I hardcode the delay time.

Preamble/disclaimer:

"active" is a vague term that has more than one meaning: I interpreted first to mean "focussed", then to mean "frontmost", and then to mean "exists"; but running your script up to the point where it creates a new movie recording, it turns out that the window created is immediately focussed, immediately frontmost, and, of course, it necessarily exists.

▸ It's not clear why you point out that you "hardcode" the delay time: was this because you would prefer to set the delay at run time, which implies being able to predict its value ahead of time; or was it because you don't want to use a delay at all, which would be a shame because that's exactly the way to do it (illustrated below).

The perceived problem

Looking through your script and testing it on my Macbook, it appears what you're wanting to set the size and position of the window that is created for the new movie recording, but finding that AppleScript will set these properties before the window is fully initialised (into a state where it is ready to record), during which time QuickTime resizes the window to accommodate the input source, thus "undoing" your adjustments.

Your script, as it is, doesn't in fact work, as it tests for the window's existence before advancing the script, and, as mentioned above in my preamble, the window exists immediately, which is to say that it gets created before it gets fully initialised (which is actually a really stupid thing for Apple to have done). Therefore, when I ran it on my system, the issue described above is annoyingly persistent.

So, to me, the problem seems to how to workaround this jarring behaviour of seeing a window created one size, then grow, then shrink, and then grow again. Ideally, if it were me, I would like the window to just appear, set at the size and position of my choosing.

Assuming this describes your objective too, then...

Suggested solution

NB. If you just need to know the time, and not especially how the clock works, skip to the end where there's a script. But, if you encounter any problems, do read the instruction manual before picking up the phone.

Firstly, we're not going to use System Events to adjust the frame of a window in an application that is scriptable, because scriptable applications provide a means to do this already, using the bounds property of a window object. It is a four-item list of integers that equate to the coordinates of the window's top-left and its bottom-right corners. Thus, if you wish to set the size of some window to {w, h} and position its top-left corner at coordinates {x, y}, you would do this:

set the bounds of some window to {x, y, x + w, y + h}

Secondly, there's no point hinging our script's delay time on a window's existence, because it will already exist on most systems. If, on your system, you do find that an error is thrown when you reference the window of the new movie recording that tells you it can't find that particular window, i.e. error "QuickTime Player got an error: Can’t get window \"Movie Recording\"." number -1728 from window "Movie Recording", then you indeed do need to test for its existence. Remember, however, this only that its properties are now gettable and settable, but not that this is the appropriate time to get and/or set them.

Therefore, thirdly, we need a new condition to test for that reliable tells us that we can adjust the window's properties and be confident QuickTime is done re-adjusting them itself, i.e. how can we tell that the window is done initialising ?

The answer to that is discovered like so:

  1. Retrieve all the properties of the window and its document immediately after creating a new movie recording;

  2. Instigate a delay of any length, but one that's definitely long enough to give the window time to initialise fully, like delay 5 or delay 10 (depending on your patience);

  3. Retrieve all the properties of the window and its document a second time;

  4. Compare.

Only two properties change between the times before and after the window's initialisation: the bounds property of the window (obviously, since this is what's annoying us); and the natural dimensions property of its document.

We can't reliably use the bounds property of the window because we won't know its initial or final values (either one alone would have been suitable for a viable test). Thankfully, natural dimensions happens to sounds like a property that is probably size-related. As it turns out, it's an extremely helpful size-related property: it doesn't tell us what the size of the window is at any point, but it does tell us the pixel resolution of the document's video input source.

If you wonder what QuickTime is doing that takes it so long to initialise a window... It's looking for, and then loading, the feed from the video input source. Therefore, when it first creates the window, the value of the document's natural dimensions is set at {0, 0}, i.e. there is no input source at present. After everything is done and the movie is ready to record, it sets the natural dimensions to its final value.

This is when you know it's a good time to adjust the bounds of the window.

However... This only eliminates one of the two jarring window resizes. The solution to get rid of something you don't want on your screen is to hide it from view, or better still, make sure it doesn't appear on your screen in the first place.

There are three ways to open an application with AppleScript, and none of them involve a call to do shell script "open ...":

  1. activate: This is the command everyone knows, because it's the one everyone uses, and so it's pervasive, and common, but this rarely means something is the best. It opens an application if it isn't already open, makes it the frontmost application, bringing it into focus. With some applications, it also triggers either a new window to be created if one doesn't exist already (some browsers, for example), or an "Open..." dialog to let you pick a document on your computer to open, if one isn't already (TextEdit, Preview, etc.).

  2. launch: This command is underused because many people aren't aware that an application doesn't need to be at the front in order to accept AppleScript commands. It opens an application, and places it and its windows on the desktop, but not at the front, and it doesn't steal focus. This means that, whatever application one is currently working in will not get disturbed.

  3. run: This is a command that, in fairness, isn't suitable for all applications, and for those that it is, is often called implicitly without the scripter realising. That's because its purpose is to open an application without physical cues; in fact, if your dock doesn't have the indicator marking running applications, there would be zero visual trace of the application at all. It opens, but in the background. It's not frontmost, it's not focussed, it's not visible, which means its windows are hidden. But most Apple applications don't need to be visible to be scripted. However, if the application is already running and this command is called explicitly, it makes the application visible (but not frontmost).

Therefore, assuming that you are opening QuickTime where it wasn't previously running, this script implements all of the above:

property position : {1087, 497}
property size : {350, 621}

tell application "QuickTime Player"
    # if it is running then quit

    set doc to new movie recording
    repeat until doc's natural dimensions ≠ {0, 0}
        delay 0.5
    end repeat

    set win to the first window where its document = doc
    set {{x, y}, {w, h}} to {position, my size}
    set win's bounds to {x, y, x + w, y + h}

    activate
end tell

YES, there is a use of the delay command. It's needed but it's not random: it's set to a minimal value purely to slow the rate at which AppleScript re-checks the natural dimensions property, which is a far cry from simply "guesstimating" a fixed delay that many people like to do in their scripts.

You will also notice it doesn't seem to use the run command I mentioned. But hopefully, you recall that it can also get invoked implicitly, and this is one of those times: if QuickTime isn't already running, then simply starting the script with new movie recording will have stuff initialising in the background. It becomes visible by sending the activate command (but don't forget, this isn't necessary, even for the actual recording and saving processes, so it's entirely possible to do a full screen recording, save it to a file, and close QuickTime without ever having to see that it was even open).

The line commented out is an optional extra to cater for instances where QuickTime is already open. In that situation, even if it wasn't visible previously, the implicit run call will make the program visible. However, quitting the application first, then running it will keep it incognito, providing there are no open documents that first need saving.


I really hope that's what you were after, because that was a long answer for me to write, and a long one for you to read (sorry about that).