Igor's monitor (macOS)

There is the possibility to list the resolutions of the connected monitors (IgorInfo(0)). For Windows you can display the window size of Igor (as used in the MPF procedure).
Is it also possible to display on which monitor Igor is running using a Mac? (Alternative:) Is there a way to display the size of the available monitor area of Igor using a Mac?

Igor doesn't run on a specific monitor on either platform. Even on Windows the MDI window can be stretched across multiple displays.

What exactly are you trying to do? AutoPositionWindow might be helpful to you.

Actually, I just want the panel position to depend on the resolution of the "active" monitor. It is more of an aesthetic problem and it only occurs when there are several monitors with different resolutions. If it doesn't work, I just continue to use the resolution of the first monitor.

As found here https://forum.latenightsw.com/t/get-sizes-of-monitor-s-via-applescript/…

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

on run
    set theResolutions to getResolutions() of me
end run

on getResolutions()
    set resolutions to {}
    repeat with p in paragraphs of ¬
        (do shell script "system_profiler SPDisplaysDataType | awk '/Resolution:/{ printf \"%s %s\\n\", $2, $4 }'")
        set resolutions to resolutions & {{word 1 of p as number, word 2 of p as number}}
    end repeat
    # `resolutions` now contains a list of size lists;
    # e.g., with 2 displays, something like {{2560, 1440}, {1920, 1200}}
end getResolutions

Other versions exists on the referenced site. Run this or equivalent via an ExecuteScript action.

Thanks, I think is is the same result you get with IgorInfo(0). There you also get a list with the resolutions of all connected screens.
If Igor exists on all screens, you probably won't be able to easily find out which one you are on when you start the function.

Example: a 4k screen and a WQHD screen. The 4k screen is the primary monitor and Igor runs on the WQHD screen.
Igor currently reads the resolution of the primary monitor and centers the panel for this resolution. This position will not be the center of the WQHD screen and the panel will be generated on the "wrong" position.

But it is a very unlikely situation. I was just hoping that there was an Igor internal function that would tell you "you are currently on screen 2".

if you define "which one you are on" by the mouse position, you can do this using a combination of getmouse and IgorInfo(0).

Here is a function to determine the screen origin

// point and rect structures must have same units
function pointInRect(STRUCT point &pnt, STRUCT rect &r)
    return ( pnt.h>r.left && pnt.h<r.right && pnt.v>r.top && pnt.v<r.bottom )
end

function getScreenOrigin(STRUCT point &pnt)
   
    // set default value
    pnt.h = 0
    pnt.v = 0
   
    GetMouse

    STRUCT point mousePoint
    mousePoint.h = v_left
    mousePoint.v = v_top
   
    STRUCT rect screenRect
   
    string strInfo = IgorInfo(0)
    string str = ""
    int numScreens = NumberByKey("NSCREENS", strInfo)
    int i, left, top, right, bottom
   
    for (i=1;i<=numScreens;i++)
        str = StringByKey("SCREEN"+num2str(i), strInfo)
        sscanf str, "DEPTH=%*d,RECT=%d,%d,%d,%d", left, top, right, bottom
        if (V_flag != 4)
            continue
        endif
        screenRect.left   = left
        screenRect.top    = top
        screenRect.right  = right
        screenRect.bottom = bottom
        if ( pointInRect(mousePoint, screenRect) )
            pnt.h = screenRect.left
            pnt.v = screenRect.top
            return 1
        endif
    endfor
    return 0
end

 

A related problem is that NewPanel /W doesn't always work as expected when screen coordinates are negative. This looks like a bug. My workaround is to follow NewPanel with MoveWindow with the same coordinates.

Thank you, tony!

This way is more complicated than I expected, but the result is exactly what I wanted.

I see. You are after the current active screen.

The approach Tony provides suggests a feature request. It would help when IgorInfo(0) would return the screen list with the first screen in the list being the one that is active (where the mouse currently resides).

In reply to by jjweimer

jjweimer wrote:

 the one that is active (where the mouse currently resides).

You could alternatively define the active screen as the one displaying the top window. I don't think there is currently a way to figure out the top window (if you include the command window and other non-target windows).

I believe the first one is the main monitor, where Igor puts its splash screen and by default where Igor puts the MDI frame window.

Somewhat unrelated to the main topic but related to the comment from Tony, I just want to note that using MoveWindow has two caveats:

1) You need to make sure that your coordinates are in points. If you use pixels (such as with NewPanel) you first need to convert the coordinates (using ScreenResolution etc.).

2) MoveWindow actually does not draw panels beyond the current MDI window size on Windows. This means that panels can be distorted by this command if the edges happen to end up outside the current MDI window. NewPanel will instead create the panel in the designated size, no matter what.

I remember discussing the behavior of NewPanel with John at some point (maybe even related to negative input values). Tony, can you still reproduce these bugs with the latest version? Would be great to fix these and skip MoveWindow for us Windows users.

In reply to by chozo

•print igorinfo(0)
  IGORVERS:9.02;BUILD:39538;IGORKIND:pro64;FREEMEM:3730264064;PHYSMEM:17179869184;USEDPHYSMEM:260530176;NSCREENS:2;SCREEN1:DEPTH=32,RECT=0,0,1280,800;SCREEN2:DEPTH=32,RECT=1280,-900,3200,180;
•NewPanel /N=panel0/W=(1380,-800,1480,-700)
•GetWindow panel0 wsizeRM
•print v_left, v_top, v_right, v_bottom
  1380  32  1480  132
•NewPanel /N=panel1/W=(1380,-800,1480,-600)
•GetWindow panel1 wsizeRM
•print v_left, v_top, v_right, v_bottom
  1380  -800  1480  -600

OS:macOS
OSVERSION:11.7.0

I have negative screen coordinates because my laptop sits on my desk at a lower height than my external monitor. I imagine that this is not an uncommon situation.

1) Screen 1 is the main monitor of the system. Since this information is perhaps also important, another IgorInfo(x) with the output of the active monitor would be preferable to me. Somehow Igor can read this - the temporary DataBrowsers always appear on the active monitor.
2) The bug with negative values for panel positions is present in the current version. However, I have not tested the current beta.

@chozo: Good point, not to use it for windows systems. However, MoveWindow seems to assume the same input as NewPanel. Are you sure it doesn't use pixels as well? I have used different scalings under Ventura. This changes the display resolution, which is shown via IgorInfo(0). My panel is moved to the center using the calculated center of the screen for all resolutions via "pixel input".

 

@tony: On macOS the screens left or top of the main screen have negative values, too.

print IgorInfo(0)
  IGORVERS:9.01;BUILD:39200;IGORKIND:pro64;FREEMEM:424771584;PHYSMEM:17179869184;USEDPHYSMEM:164352000;NSCREENS:2;SCREEN1:DEPTH=32,RECT=0,0,2560,1440;SCREEN2:DEPTH=32,RECT=-2560,0,0,1440;

 

@Gregor: That is the tricky part with being a Mac user: For you it doesn't matter if you use pixels or points, because they happen to be the same on Mac. But this will not be the case on Windows, where the point-to-pixel ratio is 96/72 or even a different value depending on the zoom factor. You may want to test your panel code on a windows machine once in a while.

@chozo: I am lucky that i used the position for windows based on the window size without negative values. Because of your comment I use the MoveWindow operation only for Macintosh systems.

But I will try MoveWindow on windows.

this seems like an appropriate place to insert this:

// control panel units:
// res=72: pixels or points
// res=96 or 84: pixels
// res>96: points

// doesn't deal with panel expansion.
// function cpu2pixel(variable cpu)
//  return ScreenResolution > 96 ? cpu * ScreenResolution / 72 : cpu
// end

// function pixel2cpu(variable pixel)
//  return ScreenResolution > 96 ? pixel * 72 / ScreenResolution : pixel
// end

function point2cpu(variable point)
    return ScreenResolution > 96 ? point : point * ScreenResolution / 72
end

function cpu2point(variable cpu)
    return ScreenResolution > 96 ? cpu : cpu * 72 / ScreenResolution

function point2pixel(variable point)
    return point * ScreenResolution / 72
end

function pixel2point(variable pixel)
    return pixel * 72 / ScreenResolution
end

// notes

// this is for Igor 9, where we don't have to worry about PanelResolution

// cpu are pixels for screen resolutions 96 AND 84 (and 72).
// MoveSubwindow /fnum= requires pixels, not cpu - help is wrong
// MoveWindow uses points
// NewPanel uses control panel units
// Positioning controls with pos={x,y} uses cpu
// Moving controls positions with pos+={x,y} takes pixels!
// These are potentially not the same
// Button b0 pos={10, 20}
// Button b0 pos={10, 10}, pos+={0, 10}

// could alternatively define variables:

// variable cpu2pixel = ScreenResolution > 96 ? ScreenResolution / 72 : 1

please correct me if I have misunderstood any of this

EDIT: already i can see there's a mistake, edited cpu2point function.

The code using GetMouse doesn't always work as expected.

If you're working on screen2 and select a menu item on screen1 without first activating one of the application windows on screen1, GetMouse will think that the mouse is still in screen2. My use for this is to create a dialog for a file loader that gets invoked from the file menu, and it's confusing when it's drawn on the 'wrong' screen.

I don't know whether this limitation affects Gregor's application.

A feature request that would fix everything for me:

Add screen number to the output from GetLastUserMenuInfo.

Yes, the function GetMouse does not update in real time, but only every 5 (?) seconds. I have tried that. But in my case a wave has to be selected in a temporary DataBrowser before, so the mouse is on the screen for a longer time in any case.

Thanks to all!

I like to add two/tree feature requests:

- A flag for movewindow, to use directly pixel and no position.

- A flag for movewindow (for Windows), which prevents a window from being moved out outside the accessible area.

- Bugfix for negative position values (NewPanel)

Oh, right.

Expansion = PanelResolution(wName)/screenresolution

But then for cpu2pixel and pixel2cpu we need to know whether we're measuring pixels from the screen origin or the panel origin, because only the panel pixels are expanded. Ugh.

Expansion = PanelResolution(wName)/PanelResolution("")

Later versions of Igor support GetWindow panelName expand, but that simply computes PanelResolution(wName)/PanelResolution("")