トラブル続きの Lion さん

なんだかなぁ...。最近、うちの MacBook(Late 2007) はトラブル続きです。

この前はプリンタのジョブが原因でスリープしなくなりましたが、今回は WiFi につながらない。なにが原因か分からない。直った現在もなにが原因か分からない。

ことの起こりは、メニューバーにある WiFi をいったん「切」にして MacBook をスリープさせたことから始まりでした。

MacBook を利用するためにスリープを解除し、メニューバーから WiFi を「入」にしてもいっこうにつながらない。それどころか、見慣れない文字が書かれている。『ハードウェアがありません』と。なんのことやら分からない。

MacBook を再起動しても直らない。そういえば、先月は WiMAX の更新月だったような。もしかしたら、更新を怠っていたかな?と思うも、iPhone は WiFi 経由で WiMAX につながっている。

とりあえず「Console.app」を立ち上げログを表示させながら、WiFi の「入」を行う。すると、『failed to set airport power state』などと記述される。この情報をもとに再度、検索。すると、同じ原因の情報が見つかる。

このページの解決法を読んだとき、眉唾かと思いましたが直りました。解決法は、Mac を再起動するときに表示されるダイアログの「再ログイン時にウィンドウを再度開く」のチェックを外しておくだけです。

quit_dialog.png

これだけで元に戻りました。なぜかは分からないけど、おそらくその辺りでナニか不具合があるのでしょうね。

眠らない MacBook

最近 MacBook の眠りが悪いとお嘆きのあなた。そんなあなたにお勧めなのが、これ。

って、私のことなのだけど。うちの MacBook(Late 2007) は、Lion を載せて元気に働いています。

と言いたいところなのですが、最近 MacBook の蓋を閉めてもスリープしない。AppleScript で命令してもスリープしない。どのようにしてもスリープしない...。MacBook(Late 2007) では Lion さんを動かすのに非力でしたか...。

まさか、非力だろうという曖昧な結論で終わらせるわけにもいかない。で、検索してみると、同じような症状で悩んでいる人が多いみたいで...。

最初に pmset で現状を確認したのですが、このときは原因が分からず。このときに気がついていたら、いろいろな苦労をすることもなかったのですが。再起動や PRAM や PMU のリセット、アクセス権の検証にディスクの検証、Console.app を起動してログの調査...とりあえず、できることはやってみました。

しかし、pmset で表示される現在の設定に原因が書かれていました。結論から書くと、スリープを阻害する何らかのプロセスがあったわけです。

$ pmset -g
Active Profiles:
Battery Power       -1
AC Power        -1*
Currently in use:
 womp       0
 autorestart    0
 halfdim    0
 sms        1
 panicrestart   157680000
 hibernatefile  /var/vm/sleepimage
 networkoversleep   0
 disksleep  10
 sleep      0 (imposed by 16)
 hibernatemode  3
 ttyskeepawake  1
 displaysleep   25
 acwake     0
 lidwake    1

sleep が 0 になっていて (imposed by 16) となっています。プロセス ID 16 が邪魔してますってことらしいです。

最終的に行き着いたのが、Swish Movement: Update: Lion sleep woes solved。ここに書かれている通りにプロセスを調べると、スリープの邪魔をしていたのがプリンタのジョブだということが判明。

何日か前に印刷をしたもののプリンタが繋がれていない状態だったので、エラーになっていました。このジョブを削除したところ、ちゃんとスリープするようになりましたと。

しかし、なんらかのプロセスによりスリープができなくなるなんて...。しかも、これバッテリ駆動だとこの問題が発生しない。バッテリ駆動だと蓋を閉めることでスリープするのです。電源がつながっているときだけ、スリープしない。気がつきにくいことこのうえない。

今回はプリンタのジョブが邪魔をしていたってことで、問題は解決したのですが、簡単には解決しない人も多数いるようで...。みなさんの問題が解決することを祈っております。

iPhone アプリケーションの URL スキームを調べる

Launch Center という iPhone アプリケーションがあります。

iOS 5.1 になって iPhone の設定を開けなくなったのは悲しい出来事でしたが、それでも少ない手間で目的のアプリケーションを起動することができるなかなか便利なアプリケーションです。いまさらここで詳しい使い方を書くのもあれなので、いくつか参考になるところを。

このアプリケーションはいわゆるランチャーなのですが、起動することができるアプリケーションは URL スキームを持っているかどうかで決まります。 Launch Center で対応しているアプリケーションもありますが、それ以外のアプリケーションは URL スキームを持っているかどうか調べないと分からない。

調べる方法はいくつかありますが、なかなか面倒。こういうものは人力でするものではありません。

iPhone のアプリケーションはバックアップ先の Mac に保管されていると思います。この保管されているアプリケーションの中にある、Info.plist というファイルを調べると URL スキームを持っているかどうか、持っているならどういう文字列か、ということはすぐに分かります。

iPhone のアプリケーションは実際のところ Zip ファイルで拡張子 ipa を zip に変更すれば、そのまま解凍できるというのはよく知られた話です。が、これらのアプリケーションのファイル名を変えて、解凍し、Info.plist を開き、目的の文字列を探し出すのは面倒な作業です。

これらの作業(Zip に変更し、解凍)を行うスクリプトをぴよまるソフトウェアさんが公開していますが、ここまでするのも大袈裟です。

ようは Info.plist 内の特定の文字列を探し出すだけです。アプリケーションのすべては必要ありません。どうすれば、Info.plist だけを抜き取ることができるか...。AppleScript だけでは Zip ファイルを解凍せずに目的のファイルを抜き出すことはできません。

でも、python は標準で入っているよな...。python には zipfile があるよな...。

なら、両者を組み合わせればいいだけで、こういうことこそ AppleScript の得意とするところ。

アプリケーション形式の AppleScript でパッケージ内に python スクリプトを配置しています。使い方は至って単純で iPhone アプリケーション(拡張子 ipa。複数可)をこのアプレットに放り込むだけ。もしくは、アプレットをダブルクリックで起動し、拡張子 ipa のファイルを選択するだけです。

処理が終了すると、デスクトップ上に「URL Schemes.csv」というファイルを作り、その中に URL スキームを書き出します。あとは、テキストエディタで開くなり、CSV ファイルなので Numbers や Excel で開くなりしてください。

ま、いつものごとく特別にエラー処理はしていないのでご利用は、ご自身の責任でお願いします。

AppleScript Editor で作る Cocoa アプリケーション

Mac OS X 10.7 を導入したのがそもそも遅かった...というのもあるのですが、旬の話題はそろそろ次の OS ですか。そうですか。そうですか。

そんな話題で盛り上がっている中、AppleScriptObjC...略して ASOC です。

AppleScriptObjC...っていうのはいったいなんなのか?

というところから話を始めますが、そもそも AppleScript というのは Mac を使う上で面倒な『日々の同じ作業を自動化する』ために生まれたプログラミング言語。いわゆるバッチ処理ですね。

Mac で作業するっていうことはいろいろなアプリケーションを扱うってことで、Mac での作業を自動化するということは、いろいろなアプリケーションを自在に操る必要があるわけです。その『アプリケーションを自在に操る』ために用意されたのが AppleScript です。

大雑把にいってしまうと、AppleScript というのはいろいろなアプリケーションを繋ぎ合わせるためのプログラミング言語。グルー言語(糊言語)なんていったりしますが、AppleScript はまさしく糊でいろんなアプリケーションを連携させることに長けています。

AppleScript は年月を積み重ねることで様々な機能が付加され続けてきましたが、シェルスクリプトと連携することができるようになったおかげで Perl や Python、Ruby などのスクリプト言語との連携もでき、Safari を通じて JavaScript を利用することができるようにもなりました。グルー言語の面目躍如といったところでしょうか。AppleScript 単体ではできない処理もアプリケーションや他のスクリプト言語の力を借りて処理が行えたりします。

do shell script 命令を利用することで他のスクリプト言語を活用することはできたのですが、Mac OS X の Cocoa フレームワークの機能を利用することはできませんでした。が、Mac OS X 10.6 から追加された ScriptingBridge というフレームワークを利用することにより、ついに AppleScript からも Cocoa の機能を利用することができるようになったのです。

Mac OS X 10.6 では Xcode でしか AppleScriptObjC のアプリケーションを作ることができませんでしたが、Mac OS X 10.7 からは AppleScript Editor で Cocoa アプリケーションが作れるようになりました。

もう、AppleScript なんでもアリです。というか、こんな面白いオモチャいじられずにおられるものか。

では、さっそく AppleScript Editor で Cocoa アプリケーションを作ってみましょう。

AppleScript Editor を起動し、「ファイル」メニューの「テンプレートから新規作成」メニューにある「Cocoa-AppleScript Applet.app」をクリックします。

template_menu.jpg

すると、保存されているテンプレートをもとに新しいアプレットが作成され、編集が行えるようになります。

テンプレートからアプレットが作成されたら、すでに Cocoa の機能を利用できる環境が整っています。おもむろに以下のコードを記述してみましょう。

tell current application's NSDistributedNotificationCenter's defaultCenter()
    addObserver_selector_name_object_(me, "update:", "com.apple.iTunes.playerInfo", missing value)
end tell

on update_(aNotification)
    set userInfo to aNotification's userInfo
    if (|Player State| of userInfo) as text is "Playing" then
        tell me to activate
        display dialog (|Name| of userInfo as text) with title (|Artist| of userInfo as text) with icon 1 buttons {"OK"} default button 1 giving up after 5
    end if
end update_

on quit
    tell current application's NSDistributedNotificationCenter's defaultCenter()
        removeObserver_(me)
    end tell

    continue quit
end quit

Objective-C のプログラムを AppleScript のスクリプトにどのように変換すればいいかは、AppleScriptObjC Release Notes に書かれています。

スクリプトは iTunes からの通知を受け取って曲の変わり目にその曲の情報を表示するというものです。

実行は、通常のスクリプトと同じように「スクリプト」メニューの「実行」を選択すればいいのですが、選択するとシートが表示されます。

run_application_sheet.jpg

ここでは必ず「アプリケーションを実行」を選択してください。「スクリプトを実行」を選択すると、通常の AppleScript として実行され、Cocoa の機能は利用できません。

シートの表示が煩わしい場合は、「スクリプト」メニューの「アプリケーションを実行」を選択すればシートは表示されず、すぐに実行されます。

スクリプトはアプリケーションとして実行されるので、明示的に終了させないといつまでも起動したままになります。通常のアプリケーションと同じようにアプリケーションメニューの「終了」を選択します。

アプリケーションとして実行されるということは AppleScript Editor でのデバック機能は利用できないということです。結果や実行途中のイベントも取得できません。これが困ったところで、現在のところデバックするには log 命令を利用して Console.app にログを表示するぐらいしか方法がありません。

ほかの注意点としては、display dialog 命令で NSString を表示する際には明示的に型変換を行うといったことがあげられます。これは、NSString だけのことではなく、Cocoa のクラスを AppleScript で利用する際にはこの型の変換を常に意識しておく方がいいです。

また、current application 経由で Cocoa の機能を呼び出しているため、current application を省略することもできません(短く記述したいなら、my でも it でも可)。

総体的には手っ取り早く Cocoa の機能を使ったアプリケーションを作るには選択肢として有りだと思うのですが、デバック機能が log 命令ぐらい(ファイルに書き出したり、ダイアログも使えますが)しかないのが致命的です。GUI の構築に手間がかかるというのも、その辺りを期待していた人には問題になるかも。

Xcode で作った ASOC アプリケーションのコードをそのまま流用できないというのもなんだかなぁというところです(スクリプトそのものはコピーアンドペーストで利用できます。Xcode はスクリプトをテキストファイルとして保持しているけど、AppleScript Edito ではコンパイル済みのスクリプトファイルでないと利用できないので)。

とりあえず、Cocoa の機能を呼び出せることは分かったけど、これを使ってなにができるか?、どこまで利用できるのか?といったことが問題になってくると思います。例えば、GUI を利用したいとか、クラス間の連携だとか...。その辺りのことは、また次回にでも。

Making Application using ASOC

AppleScriptObjC の覚書で色々と気がついた所を書きましたが、それらは実際に触ってみないと分からないことだったりします。Hello World を表示するアプリケーションを作りながら、色々と確認してみます。

Xcode や Interface Builder の使い方は、ここでは取り扱いません。それらは既に優秀な解説があります。知識としては、Cocoa はじめの一歩から手に入る Become An Xcoder ぐらいの知識が必要です(後は練習問題 12 ぐらいまでができれば大丈夫です)。訳者様に感謝です。

HelloWorld アプリケーションの UI は以下のようになります。

ASOCHelloWorld_UI.png

では、多くを端折っていきます。Xcode で Cocoa-AppleScript Application の新規プロジェクトを作成したら、アプリケーションのコントローラーを追加します。「ファイル」メニューの「新規ファイル...」から AppleScript class を選択します。NSObject のサブクラスにしておきます。ファイル名は AppController としておきます。

ASOCHelloWorld_AddFile.png

AppController.applescript を開き、アウトレットとアクションを追加します。

script AppController
    property parent : class "NSObject"

    -- Outlets
    property _window : missing value
    property textField : missing value
    property helloButton : missing value

    -- Actions
    on greeting_(sender)
        textField's setStringValue_("Hello, World")
    end greeting_
end script

アウトレットは property で宣言し、値は missing value にしておきます。アクションは引数を一つ取るハンドラとして定義します。引数を取るのでアンダースコアが必要です。Objective-C で書くなら次のようになります。

IBOutlet NSWindow *window;
IBOutlet NSTextField *textField;
IBOutlet NSButton *helloButton;

- (IBAction)greeting:(sender);

これらは通常ヘッダファイル(.h)の方に記述しますが、ASOC では、一つのスクリプトオブジェクトがヘッダファイル(.h)と実装ファイル(.m)を兼ねています。だから、上記のように書けてしまいます。あと、型の指定は当然できませんし、IBOutlet や IBAction などのキーワードも ASOC では利用できません。

なら、Interface Builder はどうやってそれらを識別するのかというと、識別されません。Interface Builder 上では全てが表示されます。ハンドラやプロパティが増えると、いささか鬱陶しいことになります。

ということで、MainMenu.xib を開いて Interface Builder で UI を作成し、アウトレットとアクションを接続します。

まず、MainMenu.xib のウィンドウに Library パレットから Object を追加します。

ASOCHelloWorld_AddObject.png

この Object を選択したまま、Inspector パレットで Class を AppController にします。

ASOCHelloWorld_ClassInspector.png

これで Interface Builder で AppController で定義したアウトレットとアクションが接続できるようになります。

ASOCHelloWorld_TargetAndAction.png

このような感じになります。保存したら Interface Builder での作業は終わりです。Xcode に戻って「ビルドと実行」を行います。アプリケーションが起動したら、ボタンを押してみてテキストフィールドに「Hello, World」と表示されるのを確認してください。

ASOCHelloWorld_UI.png

以上の作業は、AppleScript Studio での作業とは全く異なります。というより、Cocoa/Objective-C でアプリケーションを作るのとほとんど同じです。その気になれば、バインディングも使えます。

では、このアプリケーションを叩き台に色々と調べてみます。まず、スクリプトオブジェクトの外にハンドラを定義します。

on greeting()
    display dialog "Hello, World"
end greeting

greeting_ からこのハンドラを呼び出すように変更します。

on greeting_(sender)
    -- textField's setStringValue_("Hello, World")
    greeting()
end greeting_

実行してもエラーになると思います。これはどのようにしても無理なようで、スクリプトオブジェクト外にあるハンドラは呼び出すことができません。では、どうするかというとスクリプトオブジェクトにしてしまいます。

script HelloWorldDialog
    on greeting()
        display dialog "Hello, World"
    end greeting
end script

このようにしておけば、通常のようにスクリプトオブジェクトのハンドラを利用できます。

on greeting_(sender)
    -- textField's setStringValue_("Hello, World")
    HelloWorldDialog's greeting()
end greeting_

つまり、これはクラスの定義ではありません。スクリプトオブジェクトの定義です。ゆえに、このスクリプトオブジェクト内ではメソッドを作成するように引数の数だけアンダースコアは必要ありません。

しかし、下手にこのスクリプトオブジェクトの親を指定してしまうと、クラスとして扱われるようになってしまいます。

script HelloWorldDialog
    -- NSObject などを継承するとクラスになる
    property parent : class "NSObject"

    on greeting()
        display dialog "Hello, World"
    end greeting

    on greeting_(yourName) -- 引数があるのでアンダースコアが必要になる
        display dialog "Hello, " & yourName
    end greeting_
end script

スクリプトオブジェクトをそのまま利用するか、クラスとして利用するか。どちらも一長一短です。クラスとして利用するなら、別のファイルにしていても property で指定するだけでそのクラスのメソッド(ハンドラ)が利用できます。が、メソッドの命名規則は Objective-C に準じます。

他方、スクリプトオブジェクトとして利用すると、Objective-C の命名規則から逃れられますが、別ファイルにしたときに読み込みが面倒になります。awakeFromNib などを利用して読み込みますが、path to me は利用できないので、NSBundle を利用します。

on awakeFromNib()
    -- load script object.
    tell NSBundle's mainBundle()
        set theFile to pathForResource_ofType_("HelloWorldObject", "scpt")
    end tell
    set HelloWorldObject to (load script (theFile as text) as POSIX file)
end awakeFromNib

AppleScript の me は ASOC ではクラス自身を表すので、path to me は利用できません。また、上記では pathForResourceofType が返した NSString を AppleScript の text に型変換しています。AppleScript では NSString をそのまま利用できないようです。

Cocoa/Objective-C では色々と便利な関数が用意されています。それらは、ASOC では利用できません。例えば、矩形を表す NSRect を作成する NSMakeRect といった関数は使えません。これらはどのように作るのかというと、AppleScript の record クラスで代用します。

set rect to {origin:{x:10, y:10}, |size|:{|width|:100, height:100}}

このような record を作り、Objective-C のメソッドに渡せばいいようです。NSRange、NSSize、NSPoint なども同様です。NSLog は AppleScript の log 命令で代用できます。

アプリケーションを作成している時、特定のクラスを利用したい時があります。先ほどの NSBundle のように。Cocoa/Objective-C なら特に意識もしないで NSBundle のクラスメソッドを利用できたりするのですが、ASOC の場合、利用したいクラスを property で指定しておく必要があります。具体的には次のようになります。

property NSBundle : current application's class "NSBundle"

この property をどこで宣言しておくかというと、クラス(スクリプトオブジェクト)の外か、クラスの property として宣言します。

-- スクリプトのトップで宣言
property NSBundle : current application's class "NSBundle"

script AppController
    property parent : class "NSObject"
    -- クラスで宣言
    -- property NSBundle : current application's class "NSBundle"
end AppController

これで NSBundle を利用できるようになります。Objective-C の import のようなものかと思うけど、そうではないようで、一気にクラスを参照したいがために AppKit.h や Cocoa.h を指定してもだめなようです。

property AppKit : class "AppKit" -- 利用できない

このようにクラスを property で参照しておくと、クラスが持っている定数等が利用できるようになります。

-- NSBundle's notification key
-- log NSBundle's NSBundleDidLoadNotification
log current application's NSBundleDidLoadNotification

その際、current application を通して定数を指定するようにします。コメントアウトしている方は利用できません。NSWindow の初期化処理を参考に。

script CustomWindow
    property parent : class "NSWindow"

    on initWithContentRect_styleMask_backing_defer_(contentRect, aStyle, bufType, frag)
        continue initWithContentRect_styleMask_backing_defer_(contentRect, ¬
            current application's NSTexturedBackgroundWindowMask, ¬
            current application's NSBackingStoreBuffered, ¬
            false)

        return me
    end initWithContentRect_styleMask_backing_defer_
end CustomWindow

横長になるのは AppleScript の宿命です。このように利用します。初期化処理ではスーパークラスの初期化処理を最初に呼び出しますが、ASOC では continue を使ってスーパークラスの初期化を行います。また、初期化の最後に Objective-C では self を返しますが、ASOC では me を返します。

Cocoa/Objective-C のメソッドの中には AppleScript の予約語になっているものがあります。例えば、size や width もそうですし、set や center といった語は AppleScript で定義されています。NSWindow にはウィンドウをディスプレイの真ん中に移動させる center というメソッドがありますが、これを利用するには | でメソッドを囲むようにします。

_window's |center|()

ちなみに上記は以下のようにも記述できます。

tell _window to |center|()
|center|() of _window

どの書き方でも構いません。Objective-C は以下のようにメソッドを連続して記述することがあります。

NSString *string = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];

ASOC で同じように記述するなら、s を使った以下の書き方が分かりやすいかもしれません。

set str to NSString's alloc()'s initWithData_encoding_(theData,current application's NSASCIIStringEncoding)'s autorelease()

横長なのは Objective-C でも AppleScript でも同じですね。今回は Objective-C の視点から ASOC を見てみました。ASOC のいいところは、AppleScript で Objective-C のような構文を記述しながら、既存の AppleScript を混在できるところにあります。

on awkeFromNib()
    tell application "Finder"
        set loc to insertion location as text
        textField's setStringValue_(loc)
    end tell
end awakeFromNib

Cocoa/Objective-C ほど面倒ではなく、AppleScript Studio ほどイライラせずにすみます。PyObjC のプロジェクトテンプレートが Xcode 3 からなくなったのには驚きましたが(古い Xcode から移植しましたら使えました)。ASOC がいつまでサポートしてくれるのでしょう。AppleScript Studio や PyObjC に比べると、サポートの手間は少ないと思うのですが。

AppleScriptObjC 覚書

いまさら感がありありなのですが、AppleScriptObjC。通称、ASOC。Mac OS X 10.6 Snow Leopard とともに紹介されたので、既に登場から 1 年以上経っているわけですが。そろそろ、資料も揃ったことだろうとネット上を検索してみるが...これがなんとも少ない。

困ったものです。

日本で AppleScriptObjC をキャッチアップしているのは唯一ぴよまるソフトウェアさんぐらいしか見当たりません。

...困ったものです。とりあえず、Mac OS X Automation で公開されているチュートリアル動画を参考にいくつかアプリケーションを作ってみました。

アプリケーションを作っているときに気がついたことを箇条書きで書いていきます。

  • ASOC でアプリケーションを作るのは、Cocoa/Objective-C でアプリケーションを作るのと同じ。
  • AppleScript Studio とは異なる。
  • AppleScript の知識より Cocoa/Objective-C の知識が必要。
  • ASOC は、Cocoa/Objective-C でアプリケーションを作成したことがあるなら、すぐに理解できる(と思う)。
  • ASS アプリケーションを ASOC にそのまま移植するのは難しい。
  • 逆に Cocoa/Objective-C アプリケーションを ASOC に移植するのが簡単かというと、諸般の事情により一筋縄にはいかない。
  • ASOC は Cocoa の機能を全て利用できる...といったことを言われるが、そんなことはない。現状では利用できないものも多々ある。例えば、モーダルダイアログは利用できるが、シートは利用できない。

次にプログラムを書いているときに気がついたことなど。

  • ASOC のプロジェクトには登録されてるファイルはアプリケーションのデリゲートとして登録されている。
  • ASOC のクラスはヘッダファイル(.h)と実装ファイル(.m)がない。
  • ASOC のクラスは一つのスクリプトファイル(というより、スクリプトオブジェクト)で定義する。
  • スクリプトオブジェクト = クラスなので、一つのスクリプトファイルで複数のクラスを定義できる。
  • 継承は AppleScript の parent 属性を利用する。
  • テンプレートでは parent に NSObject が指定されているが、実はなくてもいい。スーパークラスに NSObject が密かに指定されている...みたい(継承をたどっていくと BAGenericObject に突き当たる)。
  • 親の指定がされていない AppleScript のスクリプトオブジェクトを継承元に指定することができる。
  • 継承元が指定されていない AppleScript のスクリプトオブジェクトをクラスとして扱うことができる。
  • 継承元が指定されていない AppleScript のスクリプトオブジェクトをクラスとして扱えば、クラスとして振る舞う。AppleScript のスクリプトオブジェクトとして扱えば、スクリプトオブジェクトとして振る舞う。
  • クラスで利用する変数(クラス変数やインスタンス変数)は AppleScript の property で定義する。
  • クラスのメソッドは AppleScript のハンドラで定義する。
  • Objective-C のメソッドはコロンで引数を表すが、ASOC ではアンダースコアで表す。drawRect: は drawRect_ になる。
  • このため ASOC 内でメソッドを定義した時、引数の数だけアンダースコアが必要になる。2 つの引数を取る append(x, y) があったとする。これは、ASOC のクラス内では appendWithX_andY_(x,y) といった形になる。Objective-C でメソッドを定義するのと同じだ。
  • メソッドの返り値や引数に型の指定はない。
  • Objective-C に用意されているメソッドの中には AppleScript で予約されているものがある。set や center 等。それらのメソッドを利用するには | でメソッドを囲む。
  • クラス内で他のクラスを利用するには、そのクラスを property を利用して参照する。
  • クラス(スクリプトオブジェクト)定義の外でハンドラを定義しても利用できない。Objective-C の関数のようなことはできない。
  • スーパークラスのメソッドは、continue を使って呼び出す。
  • NSRect や NSSize、NSPoint 等は AppleScript のレコードで定義できる。
  • 引数に NSArrayを取る Objective-C のメソッドには AppleScript の list クラスを渡すことができる。
  • 引数に NSDictionary を取る Objective-C のメソッドには AppleScript の record クラスを渡すことができる。
  • NSString と AppleScript の text は同じではない。引数に NSString を取る Objective-C のメソッドには AppleScript の text クラスを渡すことができる。が、NSString を AppleScript で利用するには型変換が必要(な時がある)。
  • Objective-C のメソッドは ASOC で利用できるが、簡易に利用するために用意されている関数群(NSMakeRect() や NSLog())等は、ASOC では利用できない。
  • NSTimer や通知などに利用するセレクタは文字列で指定する。その際、引数はコロンで表す。アンダースコアではない。
  • Objective-C の nil は AppleScript の missing value で代用。
  • path to me は利用できない。ASOC では me は自身のクラスを表す。
  • ASOC は既存の AppleScript の言語仕様を拡張しているわけではない。利用できるのは AppleScript 言語のみ。これが、いくつかの面倒を引き起こす。例えば、論理積や論理和を取りたいとき。C 言語の & や | は利用できない。
  • ASOC で Objective-C のカテゴリやプロトコルを定義することはできない。

と、思いつくままに羅列。読んだだけでは意味が分からないものもあると思いますが、細かいことはまた次回。


Snow Leopard で Dock の使い勝手が良くなったのだけど...

Snow Leopard から Dock の設定(「システム環境設定」にある)で「ウィンドウをアプリケーションアイコンにしまう」という設定が追加されました。従来まではウィンドウをしまうと Dock にずらずらっとウィンドウが並んで格納されていました。これだと Dock がウィンドウで埋められてみっともないことになっていました。

Snow Leopard から追加された「ウィンドウをアプリケーションアイコンにしまう」という設定を有効にすると、ウィンドウが Dock 内にある各アプリケーションに格納されるようになります。これで、Dock がいろんなアプリケーションのウィンドウで埋め尽くされることがなくなって、快適...なはずなのですが、問題はこのようにしてアプリケーションに格納したウィンドウをすべて元に戻したいとき。

ちょっと調べただけなのですが、どうもアプリケーションアイコンに格納したウィンドウ全てを一度で元に戻す方法はないようで...(調査不足かもしれませんが)。

最初のうちはウィンドウを一つずつ手動で元に戻していたのですが...これが、面倒。で、Dock に格納しているウィンドウをすべて元に戻す AppleScript を書く。

Script Editor で開く

tell application id "com.apple.systemevents"
    set front_application to a reference to (processes whose visible is true and frontmost is true)
    if (count front_application) is 0 then return
    set app_id to bundle identifier of (item 1 of front_application)
end tell

tell application id app_id
    try
        set window_list to a reference to (windows whose miniaturized is true)
        if (count window_list) is 0 then return
        set miniaturized of window_list to false
    on error msg number num
        activate
        display dialog (num & ": " & msg) as text with icon 1
    end try
end tell

こういうとき、System Events があると助かります。特定のアプリケーションだけではなく、すべてのアプリケーションを対象に処理を行うことができるから。

最前面にあるアプリケーションに対して実行しますが、アプリケーションによってはエラーがでるかもです。とりあえず、うちでは使えているので無問題。

application id を利用しているので Mac OS X 10.5 以降で利用可能。それ以前の環境では application id を指定している部分を変更すれば、利用できます。

スクリプトメニューなどに入れてご笑味くださいませ。