TL;DR
現在のデスクトップにFinderのウィンドウが開いていればそのウィンドウを最前面にする、開いていなければFinderの新規ウィンドウを作成するAppleScriptを作成した。
Motivation
OS X(macOS)の仕様で私が一番改善してほしいと思っていることの一つに、「複数の仮想デスクトップ(これは正確にはWindowsでの呼び方?で、OS XではSpaces という)を利用しているときに、現在のデスクトップ(Spaceとも言うが、以下これはデスクトップで統一する)で“新規ウィンドウで開く"ための機能がないこと」が挙げられる。
現状
アプリのウィンドウがすでに他のデスクトップで開いてある場合(あるいはアプリの開くデスクトップの割り当てが設定されている場合)は、Dockのアプリアイコンをクリックしたら、現在のデスクトップからアプリのウィンドウが開いてある(または設定されている)デスクトップに移動させられるか、開いてあるアプリのウィンドウが元のデスクトップから消えて現在のデスクトップに移動する。現在使っているデスクトップで新規ウィンドウを開くには、Dockのアプリアイコンを右クリックして“新規ウィンドウで開く"に相当する項目をクリックする必要がある。
やったこと
ブラウザだったら何個もウィンドウを開いても問題ないが、FinderとかTerminalだと、何個も開いていたら煩わしいので、毎回新規ウィンドウを開くのはやめたい。
そこで、Finderにおいて、現在のデスクトップに所望のアプリのウィンドウが開いていればそのウィンドウを最前面にする、開いていなければ新規ウィンドウを作成する
AppleScriptを作成した。Automatorでアプリケーションにし、ショートカットキーを割り当てれば、ワンクリックで、「現在のデスクトップにFinderのウィンドウが開いていればそのウィンドウを最前面にし、開いていなければFinderの新規ウィンドウを作成する」ことができる。
Source
大まかな流れは、
(i) Finderが起動していない場合
起動して現在のデスクトップに新しいウィンドウを作る
(ii) Finderが起動している場合
(a) Finderのウィンドウが現在のデスクトップで開かれている場合
activateにして最前面に持ってくる
(b) Finderのウィンドウが現在のデスクトップで開かれていない場合
現在のデスクトップに新しいウィンドウを作る
Finderが起動していない場合、起動して現在のデスクトップに新しいウィンドウを作るコードは以下
if application "Finder" is not running then
tell application "Finder"
launch
make new Finder window to "Macintosh HD:Users:kt:Downloads"
set bounds of window 1 to {670, 300, 1500, 810}
set frontmost to true
end tell
activate
で起動させる。
make new Finder window to "Macintosh HD:Users:kt:Downloads"
これはFinderのダウンロード(Users/kt/Downloads)を開く。
set bounds of window 1 to {670, 300, 1500, 810}
{左上X座標,左上Y座標,右下X座標,右下Y座標}にウィンドウをつくる。
set frontmost to true
で最前面に持ってくる。
現在の仮想デスクトップにFinderのウィンドウが開かれている場合のコードが以下。
tell application "System Events"
get (the name of every application process whose class of windows contains window)
repeat with process_name in the result
if ((process_name) as string is equal to "Finder") then
tell application "Finder"
activate
end tell
end if
end repeat
略
end tell
get (the name of every application process whose class of windows contains window)
これで、現在のデスクトップで開かれているウィンドウのアプリ一覧を取得する。
if ((process_name) as string is equal to "Finder") then
その中にFinderがあれば
tell application "Finder" activate end tell
activateにする。
現在の仮想デスクトップにFinderのウィンドウが開かれていないがアプリ自体は起動している場合は以下
get (the name of every application process whose background only is false and class of windows does not contain window)
repeat with process_name in the result
if ((process_name) as string is equal to "Finder") then
tell application "Finder"
make new Finder window to "Macintosh HD:Users:kt:Downloads"
set bounds of window 1 to {670, 300, 1500, 810}
activate
end tell
end if
end repeat
get (the name of every application process whose background only is false and class of windows does not contain window)
で、現在のデスクトップにはウィンドウがないが、起動はしている状態のアプリ一覧を取得している。
Full Sourceは以下。
--もしFinderが起動していない場合、起動して現在の仮想デスクトップに新しいウィンドウを作る
--もし現在の仮想デスクトップにFinderのウィンドウが開かれている場合、activateにして最前面に持ってくる
--もし現在の仮想デスクトップにFinderのウィンドウが開かれていないがアプリ自体は起動している場合、現在の仮想デスクトップに新しいウィンドウを作る
--もし非表示の場合、現在の仮想デスクトップに新しいウィンドウを作る
if application "Finder" is not running then --もしFinderが起動していない場合、起動して現在の仮想デスクトップに新しいウィンドウを作る
tell application "Finder"
launch --ここactivateにしたら、以前開いていたデスクトップにかってに移動してしまう。
make new Finder window to "Macintosh HD:Users:kt:Downloads"
set bounds of window 1 to {670, 300, 1500, 810} --set bounds of window 1 of application "'アプリケーション名'" to {左上X座標,左上Y座標,右下X座標,右下Y座標}
set frontmost to true --activateしているのになぜか最前面に来ないのでこの行を追加している。activeでも良いはず
end tell
else
tell application "System Events"
get (the name of every application process whose class of windows contains window)
repeat with process_name in the result
if ((process_name) as string is equal to "Finder") then --もし現在の仮想デスクトップにFinderのウィンドウが開かれている場合、activateにして最前面に持ってくる
tell application "Finder"
activate --activateコマンドはアプリが起動していなければ起動し(ただしそのままだと最前面には表示せずにbackground状態、隠した状態になる)、起動していればアプリのウィンドウを最前面に表示する。「アプリケーションが起動しており、なおかつ、ウインドウが背面に表示されている状態」だと上手く前面に表示されるが、「アプリケーションは起動していてもウインドウが閉じられている状態」だとメニューバーはactiveになるがウインドウが表示されない。)
end tell
end if
end repeat
get (the name of every application process whose background only is false and class of windows does not contain window)
repeat with process_name in the result
if ((process_name) as string is equal to "Finder") then --もし現在の仮想デスクトップにFinderのウィンドウが開かれていないがアプリ自体は起動している場合、現在の仮想デスクトップに新しいウィンドウを作る
tell application "Finder"
make new Finder window to "Macintosh HD:Users:kt:Downloads"
set bounds of window 1 to {670, 300, 1500, 810} --set bounds of window 1 of application "'アプリケーション名'" to {左上X座標,左上Y座標,右下X座標,右下Y座標}
activate
end tell
end if
end repeat
get (the name of every application process whose background only is false and visible is false)
repeat with process_name in the result
if ((process_name) as string is equal to "Finder") then --もし非表示の場合、現在の仮想デスクトップに新しいウィンドウを作る
tell application "Finder"
activate
make new Finder window to "Macintosh HD:Users:kt:Downloads"
set bounds of window 1 to {670, 300, 1500, 810} --set bounds of window 1 of application "'アプリケーション名'" to {左上X座標,左上Y座標,右下X座標,右下Y座標}
activate
end tell
end if
end repeat
end tell
end if
導入
Automator>新規>アプリケーション>AppleScriptを実行>ソースをコピペ>保存
最後に
当初は、Terminalでやろうと思っていた。
defaults read com.apple.spaces | plutil -convert json - -o - | jq '.SpacesDisplayConfiguration'
これで仮想デスクトップの情報を取得でき、仮想デスクトップの数などの情報は正しそうだった。しかしCurrent Space
がなぜかどこのSpaceでこのコマンドを実行しても変わらず、よくわからなかった。同じ状況の人がいた。
現在のデスクトップで開いているウィンドウを取得するのが大変だったが、AppleScriptでなんとかできた。これがあれば、私が最も改善してほしい「再起動したら一つのデスクトップにウィンドウが集中してしまう」問題を回避できるかもしれない。これは(勝手に)全人類の悩みだと思っているのでなんとか解決方法を考えたい。
Terminal
if application "Terminal" is not running then
tell application "Terminal"
launch --ここactivateにしたら、以前開いていたデスクトップにかってに移動してしまう。
do script ""
set bounds of window 1 to {250, 550, 840, 940}
activate
end tell
else
tell application "System Events"
tell application "Terminal"
do script ""
set bounds of window 1 to {250, 550, 840, 940}
activate
end tell
end tell
end if
iTerm
if application "iTerm" is not running then
tell application "iTerm"
activate application "iTerm"
delay 1
set bounds of window 1 to {250, 550, 840, 940}
end tell
else
tell application "System Events"
tell application "iTerm"
create window with default profile
set bounds of window 1 to {250, 550, 840, 940}
activate
end tell
end tell
end if