Get the current window's screen info
Is your feature request about something that is currently impossible or hard to do? Please describe the problem.
Background: I have multiple machines and two screens on one of them. On my main machine, on the secondary screen where I usually run MacVim, I have my font to :h16, but I need it at :h12 (or so) on my main laptop screen (or on my secondary machine where there is no secondary screen).
Describe the solution you'd like
I would like to be able to have a function in MacVim return the current window's screen information—screen width / height in pixels, screen name, other details; similar to the output of system_profiler SPDisplaysDataType:
Graphics/Displays:
Apple M4 Pro:
Chipset Model: Apple M4 Pro
Type: GPU
Bus: Built-In
Total Number of Cores: 16
Vendor: Apple (0x106b)
Metal Support: Metal 3
Displays:
Color LCD:
Display Type: Built-in Liquid Retina XDR Display
Resolution: 3024 x 1964 Retina
Main Display: Yes
Mirror: Off
Online: Yes
Automatically Adjust Brightness: Yes
Connection Type: Internal
If possible, it would be nice to have an event (WindowScreenChanged or something like that) which could be used to trigger when the window has been moved to a different screen or the screen has been resized or something.
Describe alternatives you've considered
I don't think that there are alternatives which let me know which screen the current window is on, even if some of this could be executed via osascript.
Huh, that's an interesting thought. I wonder if this should be a cross-platform Vim GUI API. It does seem like it needs both an autocmd and a function to query it. Let me think about it a little. I do see the value of this.
There is (or at least used to be) a neat little CLI app called screenresolution (check Homebrew) that returns the screen res and other info. I used to use it all the time in a plugin for moving the MacVim window around. You might check to see if it can return the current screen.
Unfortunately, it doesn't know anything about the "active" screen. (The first run was on my secondary screen; the second run was on my primary screen.)
│ screenresolution get
2025-01-12 19:50:32.924 screenresolution[30408:3876872] starting screenresolution argv=screenresolution get
2025-01-12 19:50:32.962 screenresolution[30408:3876872] Display 0: 1512x982x32@120
2025-01-12 19:50:32.962 screenresolution[30408:3876872] Display 1: 1080x1920x32@60
│ ~
│ screenresolution get
2025-01-12 19:50:43.536 screenresolution[30441:3877233] starting screenresolution argv=screenresolution get
2025-01-12 19:50:43.572 screenresolution[30441:3877233] Display 0: 1512x982x32@120
2025-01-12 19:50:43.573 screenresolution[30441:3877233] Display 1: 1080x1920x32@60
I think the bigger issue is mostly that you would want a way to query the MacVim window to see which screen it is in. It's ideal for this to be exposed by MacVim itself.
I was thinking more about it, you can actually already query the info you want. In macOS, the window position is global across all screens. The main screen usually starts at (0,0), and say if you have a screen to its left it could start at something like (-1920, -98). You can use getwinpos() within Vim to query the window position of the current GUI window and see which screen it is in.
FWIW you don't really need a third-party program (e.g. screenresolution) to query screen resolution for this purpose. Just for illustrative purpose, you can write the following Swift program which I call "screeninfo" (either run it directly in a screeninfo.swift, or ideally compile it using swiftc to get a more optimized version):
#! /usr/bin/swift
import Cocoa
var findPoint: NSPoint?
if CommandLine.arguments.count > 1 {
findPoint = NSPointFromString(CommandLine.arguments[1])
}
var output = [[String:Any]]()
for (index, screen) in NSScreen.screens.enumerated() {
if let p = findPoint {
if (!screen.frame.contains(p)) {
continue;
}
}
output.append(["frame": try JSONSerialization.jsonObject(with: JSONEncoder().encode(screen.frame)),
"main": NSScreen.main == screen,
"refreshRate": screen.maximumFramesPerSecond,
"scaleFactor": screen.backingScaleFactor,
"index": index,
"name": screen.localizedName])
}
let jsonData = try JSONSerialization.data(withJSONObject: output)
print(String(data: jsonData, encoding: String.Encoding.utf8)!)
If you call it directly it will print out a JSON info of your screens. If you pass it a point as a command-line argument (e.g. (23,45) it will only output the screen that contains this specific point.
If I run it locally I see something like this:
➜ ychin ~/Dev/testbed/swift% ./screeninfo
[
{"name":"Built-in Retina Display","index":0,"scaleFactor":2,"frame":[[0,0],[1512,982]],"refreshRate":120,"main":true},
{"name":"LG HDR 4K","index":1,"scaleFactor":2,"frame":[[-1920,-98],[1920,1080]],"refreshRate":60,"main":false}
]
Within Vim, you can call :echo json_decode(system('screeninfo ' .. '"' .. string(getwinpos()) .. '"')) (with my MacVim window on my second monitor) and it will be something like this that you can then parse in Vimscript (the "frame" of a screen is (origin, size)):
[{'refreshRate': 60, 'index': 1, 'name': 'LG HDR 4K', 'scaleFactor': 2, 'main': v:false, 'frame': [[-1920, -98], [1920, 1080]]'}]
I guess one issue is we don't have an autocmd that could detect a GUI window has moved or changed screen, so you won't have a way to automatically detect that this has happened.