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

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.

Related

How to detect which screen is the OSVR headset?

I have an WPF+SharpDX Windows application that displays to the OSVR HDK via a fullscreen window on the screen that is the HDK. This setup works well, but it requires users to state which screen the HDK is on.
I would like to have that automatically detected, but haven't seen anything in the API on which screen is the headset.
Currently I render in a window:
var bounds = dxgiDevice.Adapter.Outputs[_selectedOutput].Description.DesktopBounds;
form.DesktopBounds = new System.Drawing.Rectangle(
bounds.X, bounds.Y, bounds.Width, bounds.Height);
And _selectedOutputis the thing I'm looking for.
I don't support direct mode at this time and I'm using Managed-OSVR. The application will run on Windows 8/8.1/10.
It's been a while since I coded anything for OSVR, but here's from what I remember:
If you're running in extended mode, the OSVR is treated as a regular display. You can rearrange it as any other screen. The output location can be configured in the OSVR config file.
I used the following (Java) to retrieve the position and size to set up my window:
osvrContext.getRenderManagerConfig().getXPosition()
osvrContext.getRenderManagerConfig().getYPosition()
osvrContext.getDisplayParameters().getResolution(0).getWidth()
osvrContext.getDisplayParameters().getResolution(0).getHeight()
To clarify: I don't know if you can retrieve the id of the display in extended mode. From what I know, it's only defined as a position and size on the desktop.
I hope that it helps you, somewhat.

Detect if compositor is running

I want my UI to change design depending on whether the screen is composited (thus supporting certain effects) or not. Is it possible to
Reliably query whether the X server is running a compositing window manager
Get notified when compositing is switched on/off?
Solution:
To elaborate on Andrey Sidorov's correct answer for people not so familiar with the X11 API, this is the code for detecting a EWMH-compliant compositor:
int has_compositor(Display *dpy, int screen) {
char prop_name[20];
snprintf(prop_name, 20, "_NET_WM_CM_S%d", screen);
Atom prop_atom = XInternAtom(dpy, prop_name, False);
return XGetSelectionOwner(dpy, prop_atom) != None;
}
EWMH-compliant compositors must acquire ownership of a selection named _NET_WM_CM_Sn, where n is the screen number
To track compositor you'll need to check if selection is _NET_WM_CM_S0 is owned by anyone (assuming you are on screen 0) using XGetSelectionOwner. If not owned, acquire ownership yourself and monitor SelectionClear events to detect when compositor is started.

CGDisplayCreateImageForRect: how to ignore a specific NSWindow

I'm looking to make a sample "lens" app which show what's is visible under the current mouse location. I've used CGDisplayCreateImageForRect to get a portion of the screen under the mouse location.
Now I would to attach a transparent window at the same location of the mouse and show this lens directly under the mouse position; however under this location there is...my transparent window with the result zoom... ops!
Is there a way to exclude a particular window from the snapshot or another method to get the current image at mouse position by ignoring something behind it?
You can't do it with that function. You can use the CGWindowList API to do it: either CGWindowListCreateImage() or CGWindowListCreateImageFromArray(). These let you specify criteria to select the windows to include or an explicit list of windows.
It's not clearly documented how to obtain the window ID of one of your own windows. The supported way is probably to query information about all on-screen windows using CGWindowListCopyWindowInfo() and then use the properties to identify yours. That said, I believe that the NSWindow property windowNumber does in fact correspond the Core Graphics window ID.
#ken-thomases point me to the right direction. The function I've used to include all windows and exclude my single one is CGWindowListCreateImageFromArray().
The code below is a small example:
// Get onscreen windows
CGWindowID windowIDToExcude = (CGWindowID)[myNSWindow windowNumber];
CFArrayRef onScreenWindows = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
CFMutableArrayRef finalList = CFArrayCreateMutableCopy(NULL, 0, onScreenWindows);
for (long i = CFArrayGetCount(finalList) - 1; i >= 0; i--) {
CGWindowID window = (CGWindowID)(uintptr_t)CFArrayGetValueAtIndex(finalList, i);
if (window == windowIDToExcude)
CFArrayRemoveValueAtIndex(finalList, i);
}
// Get the composite image
CGImageRef ref = CGWindowListCreateImageFromArray(myRectToGrab, finalList, kCGWindowListOptionAll);

On Windows7 when my application hangs in maximized state then irrespective of app's window position ghost window is always created on top left corner

In certain cases our application UI thread has to do heavy processing which may take more than 5 seconds and if this happens then OS thinks that my app got hanged and hence creates a ghost window.
This ghost window is correctly created on top of my app when my app is in restored state however when my app is in maximized state, this ghost window always picks Point(0,0) as its top left corner hence it looks like app is jumping to top left on its own. Can we avoid this jumping?
I don't want to disable ghost window creation for my app. One workaround could be to PeekMessage (don't remove) after regular interval. However, if possible I would like ghost window to appear whenever OS wants but it should be exactly where my app was before going to unresponsive state.
Please note, we customize the max window size for our application by overriding WM_GETMINMAXINFO.
------------This is how we set custom window size--------------
void CHangTestDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
lpMMI->ptMaxSize.x = 1011;
lpMMI->ptMaxSize.y = 727;
CRect rectWorkArea;
SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rectWorkArea, 0 );
int ileft = (rectWorkArea.Width() - 1011)/2;
int itop = (rectWorkArea.Height() - 727)/2;
lpMMI->ptMaxPosition = CPoint(ileft, itop);
CDialog::OnGetMinMaxInfo(lpMMI);
}

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

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.

Resources