有没有办法迭代Mac OS X中所有打开的窗口?

时间:2012-07-09 20:19:00

标签: macos cocoa applescript

当您从笔记本电脑上拔下具有更高分辨率的外接显示器时,窗口大多保留其宽度,但其大小会被剪切到macbook屏幕的(较小)高度。当您重新插入显示器时,它们的尺寸仍然非常小。

我的问题是:有没有什么方法可以迭代所有打开的窗口,保存它们的大小,并在监视器重新插入后恢复它们?

2 个答案:

答案 0 :(得分:9)

以下AppleScript演示如何:

  • 遍历所有窗口
  • 检索并更改窗口位置
  • 检索并更改窗口大小

代码:

tell application "System Events"
    set theProcesses to application processes
    repeat with theProcess from 1 to count theProcesses
        tell process theProcess
            repeat with x from 1 to (count windows)
                set windowPosition to position of window x
                set windowSize to size of window x
                set position of window x to {0, 0}
                set size of window  to {100, 100}
            end repeat
        end tell
    end repeat
end tell

注意:脚本需要访问辅助设备(AfAD):
“系统偏好设置”→“通用访问”→“启用辅助设备访问”

编辑(回复评论)

从AppleScipt启用AfAD可能会改善用户体验,但每次执行脚本时都不会这样做,只有在禁用AfAD时才启用AfAD。在不通知用户的情况下启用功能是不好的做法,提示用户启用AfAD的权限。

示例:

set AccesEnables to do shell script "[ -e \"/private/var/db/.AccessibilityAPIEnabled\" ] && echo \"Yes\" || echo \"No\""
if (AccesEnables is equal to "No") then
    set askUser to display dialog "This application requires access for assistive devices. Enable this feature?" default button 2
    set answer to button returned of askUser
    if answer is equal to "OK" then
        do shell script "touch /private/var/db/.AccessibilityAPIEnabled" with administrator privileges
    else
        close
    end if
end if

答案 1 :(得分:2)

AppleScript解决方案 - 参见Anne的答案 - 是迄今为止最简单的解决方案。

如果您想将此信息提供给无法依赖的朋友,以了解如何启用辅助访问,或者更广泛地分发,请添加以下行:

do shell script ¬
  "touch /private/var/db/.AccessibilityAPIEnabled" ¬
  with administrator privileges

这将弹出通常的auth对话框,然后使用权限打开辅助访问。

实际上可以在没有辅助访问的情况下执行此操作,但它需要在CoreGraphics / Quartz Window Services中使用私有函数,即CGSPrivate.h

使用公共API,您可以轻松枚举所有窗口:

CFArrayRef windows = 
  CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
                             kCGWindowListExcludeDesktopElements,
                             kCGNullWindowID);

返回一个字典数组,每个字典包含一个kCGWindowBounds字典,它包含Height,Width,X和Y整数值。

但这些公共API严格是只读的。要实际移动窗口,你必须深入CGSPrivate.h来做这样的事情:

CGSConnection conn = _CGSDefaultConnection();
for (NSDictionary *window in windows) {
  CGSWindow wid = (CGSWindow)[[window objectForKey:@"kCGWindowNumber"] intValue];
  CGRect bounds;
  CGRectMakeWithDictionaryRepresentation([window objectForKey:@"kCGWindowBounds"],
                                         &bounds);
  CGSMoveWindow(conn, wid, bounds.origin);
}

显然,这非常讨厌,如果你真的需要分发一个不能要求辅助访问的应用程序,你应该只考虑它。

你也可以对Window Server协议进行逆向工程并直接与它对话,但这甚至更糟糕。