我正在开发一个小型 Mac 应用程序,该应用程序通常会在后台不可见地运行。但是,当用户在桌面或 Finder 中的其他位置重命名文件时,应用程序的主要功能就会发挥作用。发生这种情况时,我想显示一个类似于用户通过 Finder 更改文件扩展名时出现的对话框。因为这需要我的应用程序获得最前面的焦点(而不是 Finder),所以当用户在我的对话框中点击“确定”时,我想将 Finder 作为最前面的应用程序返回。
我目前正在使用 Apple 的Process Manager功能SetFrontProcessWithOptions()
,但在以下情况下遇到了麻烦:
- 用户在其工作区的某处打开一个 Finder 窗口
- 然后用户点击他们的桌面,使窗口失去焦点。
- 用户重命名桌面上的文件
- 我的应用程序使自己专注于使用
SetFrontProcessWithOptions()
- 用户
OK
在对话框中点击,我的应用程序使用 Finder 聚焦SetFrontProcessWithOptions()
- 当 Finder 重新聚焦时,它聚焦用户之前打开的窗口,尽管事实上当 Finder 之前处于最前面时它没有聚焦。
如果在重命名桌面上的文件之前在另一个空间中打开了 Finder 窗口,这会变得非常烦人:在这种情况下,在对话框中点击“确定”会导致 Finder 自动切换空间并返回窗口。
这只是因为SetFrontProcessWithOptions()
函数的性质,它只能聚焦给定应用程序的窗口。由于桌面显然不算作window,因此该函数反而会找到另一个要聚焦的窗口,尽管事实上用户之前没有将该窗口聚焦。
如果有人对如何做这样一种基于对话的事情有更好的想法,那就太好了,甚至可能根本不需要聚焦和不聚焦 Finder。
编辑:我发现了一种在大多数情况下修复此行为的有点丑陋的方法,但它涉及脚本桥,并且如果其中的项目被重命名,它不会重新聚焦桌面。这是我这样做的代码:
FinderApplication * app = [SBApplication applicationWithBundleIdentifier:@"com.apple.finder"];
if (!app || ![app isRunning]) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
return;
}
SBElementArray * selArray = app.selection.get;
if ([selArray count] == 0) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
return;
} else {
FinderWindow * window = [[[selArray objectAtIndex:0] container].get containerWindow].get;
if ([window isKindOfClass:NSClassFromString(@"FinderFinderWindow")]) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
} else {
// TODO: this is where I'd insert code to select the item
// on the desktop...
}
}