Lion上のQuartzComposerの問題点
OS X Lion上のQuartzComposerを使用してCamTwistのモジュールを作成する場合、重大な問題点があります。QuartzComposer上でUI項目をPublishedすることで、CamTwist上でもパラメータのSettings欄にUI項目を出すことができますが「Labeled Index」形式にした場合のポップアップメニューの文字部分が表示されず、クリックしてもポップアップしません。
このままですとLionしか動かない最近のマシンでの開発が不可能になってしまうため、どこに原因があるのかを調査し回避方法を検討したのですが、結果的に現時点では別途Snow Leopardマシンを介在させない限り回避(修正)はできないという結論に達しています。
この記事の短縮URL→ http://bit.ly/ABnf6c
まず、問題(バグ)がどこにあるのかを突き止める必要がありますが、関連しそうなのは以下の通りです。
- CamTwistのバージョン
- Quartz Composer.appのバージョン
- Quartz Composer Frameworkのバージョン
- その他の要素
■CamTwistのバージョンは関係あるのか?
現行(2012年1月)のCamTwistの最新版は2.4です。v2.4およびv2.2, v2.3を LionとSnowLeopardで起動させてLionで作成した.qtzを読ませても、どの場合もLabeled Indexのメニューは表示されません。
逆にSnowLeopardで作成した.qtzを読ませた場合、どの環境でもLabeled Indexのメニューは表示されます。
つまり作成された.qtzファイルそのものに問題があって、実行環境には依存していないということで、CamTwistのバージョンも無関係ということになります。
■Quartz Composer.appのバージョンは関係があるのか?
Quartz Composer.app(アプリ本体)は Lion版が v4.5で、SnowLeopard版が v4.0です。.app自体は/Developer/Applications にありますのでSnowLeopard版の v4.0をLion上に持って来ることは簡単にできます。(逆は起動できない)
しかし、Lion上で v4.0のQuartz Composer.app で Labeld Index項目を作成して、CamTwist上ではUIにメニューが表示されません。
つまり Quartz Composer.app自体のバージョンは無関係ということになります。
では .app以外の何かのバージョンということになりますが、何があるのでしょうか?以下はSnowLeopard上で起動した Quartz Composer.app ver.4.0ですが、ちょっと様子が違うようです。
よく見るとFramework VersionがLionの場合 5.0 (236) ですが、SnowLeopard (10.6.8) の場合は 4.2 (156.30) となっています。また余談ですが SnowLeopard (10.6.3)だと4.1 (156.13) となっています。
■Quartz Composer Frameworkのバージョンは関係があるのか?
上記のように、Quartz Composerは.appであるアプリ本体だけでなく、OS上のFrameworkのバージョンにも依存しているため、Frameworkのバージョンも検証しないと意味が無いようです。
Quartz Composer Frameworkの実体は、
/System/Library/Frameworks/Quartz.framework/Versions/Current/Frameworks/QuartzComposer.framework/Versions/Current
にありますが、2カ所ある Current はシンボリックリンクになっており、通常は同じ階層にある A ディレクトリにリンクされています。上記の場合1つ目は Quartz.framework の物で、2つ目が QuartzComposer.framework の物になりますが、通常状態では Current = A なので実際のパスは以下の通りになります。
/System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/QuartzComposer.framework/Versions/A
つまり、Aの他にB, C ディレクトリを作成して、別バージョンの Framework を共存させておいて、シンボリックリンクを張り直すことで Framework のバージョンを切り替えることが可能です。
この場合B, C ディレクトリの中身はSnowLeopardマシンから持って来ることになりますが、所有者をroot:wheelにすることを忘れないように注意します。実験目的なのでシンボリックリンクの張り替えは手動で良いのですが、頻繁に切り替えたい場合は簡単なシェルスクリプトを書いた方が良いかもしれません。
これによりQuartz Composer Frameworkのバージョンは
A = ver5.0(236) (10.7.2相当)
B = ver4.2(156.30) (10.6.8相当)
C = ver4.1(156.13) (10.6.3相当)
に切り替えが可能になりましたので、Lion上で ver4.0 (103.1) Framework ver4.2 (156.30) なQuartzComposerを起動できるようになりました。
しかし残念なことにこの状態のQuartzComposerで作成したLabeled IndexもCamTwistでは機能しませんでした。念のためにver4.0 (103.1) Framework ver4.1 (156.13) な環境でも試しましたが、結果は同じでした。
つまりQuartz Composer Frameworkのバージョンには依存しないということです。
■その他の要素・・・
より上位の Framework や Foundation に依存するとなると私の手には負えないので、発想を変えて生成された.qtz ファイルの方に着目してみます。
Quartz Composerのファイルである .qtz ファイルはbinary形式のファイルで、 .plist の一種です。SnowLeopard環境までならば、Property List Editor.app にDropすることで中を見ることができましたが、Lion環境ではProperty List Editorが廃止されXcode.appに統合されてしまったため、.qtz のままだとPreviewしてしまい中身が見られなくなっています(Xcodeの使い方が判っていないだけなのでしょうが)。
ここで .qtz は .plist 形式なことを利用して、可読なXML形式の .plist に変換をします。コマンドは以下の形式になります。
$ plutil -convert xml1 -o OutputFile.qtz InputFile.qtz
これで元のBinary形式の InputFile.qtz ファイルが XML形式の OutputFile.qtz として保存されます。逆に XML形式からBinary形式にするには、
$ plutil -convert binary1 -o OutputFile.qtz InputFile.qtz
になります。 それぞれ xml binary ではなくxml1 binary1 なことに注意してください。
なお、このXML化された .qtz ファイルもそのままCamTwistで使用することができます。可読でテキストエディタで編集ができるため、環境による差分を検証しやすくなっています。
比較に使用するのは Input という名称で Publish した4択のLabeled Indexのみを配置したパッチです。背景のClearも無い物です。
ファイルを見比べて真っ先に気付くのはportAttributesの部分です。
<key>portAttributes</key>
<dict>
<key>Input</key>
<dict>
<key>description</key>
<string>The input port.</string>
<key>name</key>
<string>Input</string>
</dict>
と
<key>portAttributes</key>
<dict>
<key>Input</key>
<dict>
<key>description</key>
<string>The input port.</string>
<key>menu</key>
<array>
<string>Unlabeled (0)</string>
<string>Unlabeled (1)</string>
<string>Unlabeled (2)</string>
<string>Unlabeled (3)</string>
</array>
<key>name</key>
<string>Input</string>
</dict>
の違いでしょう。 このUnlabeled (0)〜なarray部分は正に、 IndexのLabel部分ですので、一瞬「これか!」と思ったのですが、XML上でこれらの menu のarrayアイテムを書き足しても結果は好転しませんでした。
更に相違点を観て行くと、 rootPatch側のpublishedInputPortsの内容が違っているようです。
<key>publishedInputPorts</key>
<array>
<dict>
<key>key</key>
<string>Input</string>
<key>node</key>
<string>Splitter_1</string>
<key>port</key>
<string>input</string>
</dict>
</array>
と
<key>publishedInputPorts</key>
<array>
<dict>
<key>key</key>
<string>Input</string>
<key>node</key>
<string>Splitter_1</string>
<key>port</key>
<string>input</string>
<key>state</key>
<dict>
<key>userInfo</key>
<data>
BAtzdHJlYW10eXBlZIHoA4QBQISE
hBNOU011dGFibGVEaWN0aW9uYXJ5
AISEDE5TRGljdGlvbmFyeQCEhAhO
U09iamVjdACFhAFpApKEhIQITlNT
dHJpbmcBlYQBKwRuYW1lhpKEl5gF
SW5wdXSGkoSXmARtZW51hpKEhIQO
TlNNdXRhYmxlQXJyYXkAhIQHTlNB
cnJheQCVlgSShJeYDVVubGFiZWxl
ZCAoMCmGkoSXmA1VbmxhYmVsZWQg
KDEphpKEl5gNVW5sYWJlbGVkICgy
KYaShJeYDVVubGFiZWxlZCAoMymG
hoY=
</data>
</dict>
</dict>
</array>
このstateのdataを移植することで、CamTwist上にLabeleのメニューが表示されるようになりました。
つまり、QuartzComposerのエディタ(.app)で作成したPatchを .qtz ファイルに書き出す際に publishedInputPorts の state が書き出されないのが原因と考えられます。
とは言ってもどういうデータか判らないので、手書きで埋めることは不可能ですし、そもそも規模が大きくなれば元々手作業での修正は不可能です。ただ、この部分に関係するOS側の要素が判れば本当にどこがバグっているのかも判るかもしれません。
ちなみに、CamTwistの開発者は以下のような回答をしています。
Labelled Index Can not Publish in Lion
http://www.allocinit.com/ctforums/viewtopic.php?f=4&t=683
” It’s a confirmed Lion bug, unfortunately. I haven’t bothered to try to work around it but it seems like I probably should. ”
LionのバグだからCamTwist側じゃ直し様がないのでしょうね。
■当面の対策・・・
とは言っても、 Lionマシンで開発ができないと MacBookAir mid2011 でdendoSwitcherの開発が出来なくなって困りますので。対策は考えました。
- SnowLeopardマシンを家に常駐させる
- DropboxでMBAとフォルダを同期させる
- 投げ込みフォルダをフォルダアクションで監視する
- 追加があったらQuartzComposerで開く
- AppleScript + System Events で別名保存させる
- Dropboxで手元のMBAに変換済ファイルが戻る
フォルダアクションから起動させるため、専用のワークフロー(中身は「Fider項目を開く」とAppleScript)を作成しています。
~/Library/Workflows/Applications/Folder Actions
に保存することでフォルダアクションから選択ができるようになります。AppleScriptの中身は以下のような内容です。
tell application “Quartz Composer”
activate
end tell
tell application “System Events”
tell process “Quartz Composer”
tell menu bar 1
tell menu bar item “File”
tell menu “File”
pick menu item “Save As…”
key code 124 — →
keystroke “-conv”
key down (command)
key code 126 — ↑
key up (command)
keystroke tab
keystroke tab
keystroke tab
keystroke “s”
keystroke return
keystroke return
end tell
end tell
end tell
end tell
end tell
tell application “Quartz Composer”
activate
end tell
tell application “System Events”
tell process “Quartz Composer”
tell menu bar 1
tell menu bar item “Quartz Composer”
tell menu “Quartz Composer”
pick menu item “Quit Quartz Composer”
end tell
end tell
end tell
end tell
end tell
かなりベタな手法で別名保存しているのでファイルは1個ずつ変換させないとエラーになります。エラー処理も入っていないので、.qtz ファイル以外を投げ込むのも禁止です。
Dropboxフォルダ以下の構成
Dropbox
_┗ QCConverter (専用フォルダ※)
___┣ WatchFolder(投げ込みフォルダ、フォルダアクションの対象)
___┗ SaveFolder(別名保存フォルダ)
フォルダアクションを仕込むのはWatchFolderで、別名保存されるのはSaveFolderです。この2つのフォルダ以外のフォルダやファイルをQCConverterフォルダ内に置かないようにします。(sキーを叩いて別名保存先を選択しているため)
また、System Eventsでメニュー項目を制御するには、システム環境設定の「ユニバーサルアクセス」で「補助装置にアクセスできるようにする」にチェックを入れておく必要があります。
現在この設定になった MacBook Pro (Snow Leopard) が自宅で常時稼働しており、出先のMacBook Air (Lion) とDropboxでフォルダが同期されています。 MBAで作成した 〜.qtz ファイルをWatchFolderに入れることで、数十秒でSaveFolderに別名保存された 〜-conv.qtz が出て来ます。
この方法だと厳密には QuartzComposer ver4.5 の全機能が使える訳ではないのですが、dendoSwitcherではLabeled Index を多用しているので、これがないと使えないのです。
コメント