How to position a Cocoa window to minimize overlap with other windows? - cocoa

I'm working on a Cocoa app that has a main window and a preview window. I'd like the preview window to automatically position itself to minimize overlap with other windows — it definitely shouldn't overlap my app's main window, and it should try not to overlap other applications' windows.
How should I do this?

Apple has a sample application called Son of Grab that shows you how to consume all current windows.
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID); will give you the current windows. You can interrogate the kCGWindowBounds value to get the bounds of the returned windows.

Related

Windows API - Maximize a window across all monitors

We have a custom RDP client that we've built using the RDP ActiveX control and MFC:
https://learn.microsoft.com/en-us/windows/win32/termserv/using-remote-desktop-web-connection
In order to support multiple monitors, we use the put_UseMultimon function:
https://learn.microsoft.com/en-us/windows/win32/termserv/imsrdpclientnonscriptable5-usemultimon
This kind of works, but we have to manually stretch the window across the monitors. Maximizing the window will maximize it on one of the monitors. The experience we get is not so good, we can't really use the entire area, and the window title bar remains (when maximizing the window on one screen it disappears).
We would like to get an experience similar to mstsc, where maximizing the window will change it's style to maximized and make the window span on the entire area. Is there a way to maximize a window and make it span across all monitors?
#JonathanPotter is right.
WM_GETMINMAXINFO sent to a window when the size or position of the
window is about to change. An application can use this message to
override the window's default maximized size and position.
The following is an example to achieve this purpose. (Note: Extend from main display to the second display does work. otherwise doesn't work.)
case WM_GETMINMAXINFO:
MINMAXINFO* maxInfo = (MINMAXINFO*)lParam;
maxInfo->ptMaxPosition.x = GetSystemMetrics(SM_XVIRTUALSCREEN);
maxInfo->ptMaxPosition.y = GetSystemMetrics(SM_YVIRTUALSCREEN);
maxInfo->ptMaxSize.x = GetSystemMetrics(SM_CXVIRTUALSCREEN);
maxInfo->ptMaxSize.y = GetSystemMetrics(SM_CYVIRTUALSCREEN);
return 0;
More reference: "Multiple Monitor System Metrics" "GetSystemMetrics function".

Getting a notification when other app's window move / resize

I'm creating a screen scraping application. What I'm trying now is to fit a rectangle around the corners of the active windows of a given application (by PID).
I managed that by getting a reference to all the active windows in the workspace and using CGWindowListCopyWindowInfo to match the owner PID. Now I have an array of the active windows, but after showing the rectangle that incorporates all the windows as above stated, I didn't find a way to register to get notifications when those windows are moved and / or resized in order to resize and fit my drawn rectangle.
The following is a sample of the code I used to get the NSWindow's frames of the selected application.
pid_t pid = [selectedApplication processIdentifier];
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionAll,kCGNullWindowID);
for (NSMutableDictionary* entry in (NSArray*)windowList) {
pid_t ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue];
if (pid == ownerPID) {
// setting the bounds for each window of the application on match
CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[entry objectForKey:(id)kCGWindowBounds], &bounds);
.....
Is there any way in which I can register for updates from those NSwindows given a specific PID of an application I don't own ?
Currently this is a limitation of the APIs from Apple. Didn't find any other way to register for update NSNotifications from other applications NSWindows. Maybe this is treated as a security measure.

Cocoa Accessibility API: Hide a window

I'm looking to hide a window on OSX (not belonging to my app), but not the rest of the application. I have tried simply moving the window off the screen (like I would do in Windows), but the api always positions it at least 20 pixels away from the edge (#annoying).
Other things I have thought of:
Setting the opacity of the window to zero (can this be done?)
Minimizing the window, but it appears that the window handle becomes null once the window is minimized, so might be hard to get back
Setting the window level (i.e. desktop) or z order (can this be done?)
Moving the window to a different workspace (can this be done?)
Does anyone know of a way to do this?

Lion Full Screen menu bar doesn't slide down

I've got a small window that has no borders, titlebar, buttons, etc. I want to support full -screen mode (the new Lion kind) and I basically have all that working -- I can switch into and out of fullscreen mode and the window resizes itself, etc, no problems.
However, when I move the mouse to the top of the screen, the Menu bar with the icon to close the full screen mode does not slide down.
How do I get that working? Is it keyed off a style mask? Something else?
A-ha, the key is in what you return for
- (NSApplicationPresentationOptions)window: (NSWindow *)window willUseFullScreenPresentationOptions: (NSApplicationPresentationOptions)proposedOptions
You need to add NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationHideDock to the returned values in addition to NSApplicationPresentationFullScreen.
The only thing you need to do to make full screen mode work in Lion is to call ‑setCollectionBehavior: on your window and pass in NSWindowCollectionBehaviorFullScreenPrimary.
You don't need to do anything else. All the kiosk-mode stuff is not necessary unless you are targeting 10.6 or earlier.

Can a window be resized past the screen size/offscreen?

My purpose is to size a window to a width/height greater than the size of my physical screen programmatically under Win32. How can I do this?
On my systems it seems the maximum size of a given window is bound by the size of my screen whether programmatically or whether sizing manually by dragging the sizing cursor.
I have tried programmatically with SetWindowPos() and MoveWindow() and both cap the size of the target window. Oddly I know some people do not have this 'cap' so I wonder whether this is perhaps due to some OS setting (registry). Does anyone know something about this? Or perhaps some way to workaround it?
// Edit: new developments
I am testing on Windows XP and Windows 7. The graphics cards I'm using are a NVIDIA Quadro NVS 290 (256MB) and a Geforce 9800GT (1GB). After further investigation it looks like Windows is intercepting the message and fiddling with the parameters. For example, if you call SetWindowPos to make a target 2000x2000 it will only receive a WM_SIZE for the capped x/y.
Implement a message handler for WM_GETMINMAXINFO to stop Windows from applying the sane default behavior:
case WM_GETMINMAXINFO: {
DefWindowProc(hWnd, message, wParam, lParam);
MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMaxTrackSize.x = 2000;
pmmi->ptMaxTrackSize.y = 2000;
return 0;
}
Windows with a thick frame (to allow user resize) are restricted from growing larger than the desktop.
Try SetWindowLong() clearing the THICKFRAME (0x40000) flag.
The following should allow programatic sizing, but the user will lose the ability to resize. If you add the Thickframe back after sizing, the user can resize, but when he does so the window will immediately shrink back to the desktop limited size.
The following is from some csharp code that also removes all borders, caption, etc:
WS style = (WS)GetWindowLong(ptr, GWL_STYLE);
style = style & ~WS.BORDER & ~WS.ThickFrame & ~WS.SYSMENU & ~WS.CAPTION | WS.POPUP;
SetWindowLong(ptr, GWL_STYLE, (int)style);
A good tool to play with window settings is uuSpy.
It's like Microsoft Spy++, but allows you to modify settings like THICKFRAME.
Yes, windows can be larger than the screen (or even the sum of all your monitors). Windows can also be positioned off-screen (which some applications do as a hack to hide while remaining active).
Perhaps the Windows 7 desktop manager is kicking in and trying to "dock" those windows to the edges of your screen for you.
You might try using the slightly lower-level API SetWindowPos, which gives you control over notifications, z-order, and other stuff.
You can get a window to be larger in resolution (and even way way larger) than your screen, using the 'Infinte Screen" software:
http://ynea.futureware.at/cgi-bin/infinite_screen.pl
Here's how to use it:
Download it, run it.
In the Oversize tab, choose the Windows you want to enlarge.
Give it the Width and Height you want. Done!
Just in case you need a large screenshot (that's how I ended up here):
If you want to get a screenshot of the window, you've got a screenshot option in the same Oversize tab. (Because screenshots are normally no bigger than the screen size, even if the window is larger). Another (and better) way to screenshot the window is using Greenshot, as you can save them in .tiff and directly watching the window.

Resources