Frames and Displays

I have a two-display configuration running on Ubuntu Linux. My "main" screen is my laptop but the screen I usually "use" is a secondary, larger monitor that sits right in front of me. I have the launcher bar configured to be present on both displays.

I have noticed that when DrRacket starts up (from an icon on the launcher bar) the "loading" display shows up on the display from which I launched the application. Then, when that's done, the actual application window shows up on my laptop and I have to move it. This same behavior seems to occur with dialogs that launch from DrRacket, they show up on my laptop and I have to move them.

I started looking at the GUI API and there doesn't seem to be any recognition that there may be multiple displays. I'm not really expecting any, but its absence suggests that there is no recognition of or support for multiple displays.

Is there a way to cause new frame% and dialog% objects to show up on the same display as ... well I guess the application's main window?

To me it sounds like, you need to configure in your window manager such that
the exernal screen, if present, is the primary screen.

Exact details depend on the window manager.

Good idea. Just tried it. Doesn't make any difference. DrRacket always starts on the main display. Rebooted and tried again, just to make sure.

VSCode, IntelliJ, and Goland (the latter two are JetBrains IDEs) all seem to start on the display on which they were closed last. Tried this with the main display set each way and the behavior is the same.

There must be:

  • some way that a display can be specified to the OS when opening a window,
  • a way for an application to determine the display on which a window is shown, and
  • a place where the applications are saving this for next time.

I suspect that the solution would be something buried deep within racket/gui in the frame% implementation. My guess would be that the window creation code specifies display 0 all of the time, or doesn't specify it and that's the default. It's almost certainly platform specific code as well.

Good idea. Just tried it. Doesn't make any difference. DrRacket always starts on the main display. Rebooted and tried again, just to make sure.

What do you mean by "main display" here. The laptop screen or the screen set to primary in the window manager?

Do your window manager cache old placements of windows?
If so, you might need to flush them.

I am not using Linux, so I can't help with the concrete window manager, but
maybe others have experience with the window manager, you are using?

There are some function for dealing with multiple displays here:

https://docs.racket-lang.org/gui/Windowing_Functions.html#(part._.Global_.Graphics)

The short version is that racket/gui provides support to query the current monitor configuration, see:

https://docs.racket-lang.org/gui/top-level-window___.html#%28meth._%28%28%28lib._mred%2Fmain..rkt%29._top-level-window~3c~25~3e%29._display-changed%29%29

And then DrRacket uses that support to try to remember where you last left a window when you had the set of monitors you have currently, and then move stuff around.

This works well for me on Mac OS so my guess is that some of the racket/gui primitives aren't working for you. Perhaps trying them out and seeing what they do and if the results make sense will lead to being able to open an issue in either the racket/gui repo (if the function return wrong results for you) or in the racket/drracket repo if drracket's handling of the results could be improved.

Hth,
Robby

1 Like

It looks like display-changed signals a change to monitor configuration, not a change in what monitor is currently displaying a window. Fooling around with the code seems to confirm that. In addition, searching the DrRacket source doesn't show any use of display-changed.

The other functions mentioned also return monitor configuration information, not information about what monitor is currently displaying what window.

Looking in racket-8.9/share/pkgs/gui-lib/mred/private/wx/gtk/frame.rkt I can see the GTK calls but there's nothing like gtk_window_set_display or gtk_window_display.

I'm just not seeing any way racket/gui supports the connection between a frame% and the display (or monitor) on which it is displayed.

That's right: racket/gui provides the basic functionality (ie implements the connection to the underlying OS) and DrRacket uses it to try to match a particular monitor configuration to a particular window placement. I linked that one method because it links other related primitives.

Robby

It turns out the x,y coordinates of a window are not relative to the monitor on which the window is displayed but are absolute across a virtual space encompassing both monitors (at least on Linux).

I keep the primary monitor to the left. I am able to:

  • acquire a current x,y location from a frame% that I have moved to the secondary monitor that includes an x-value larger than the width of the primary monitor and
  • create a new window on the secondary monitor by setting an x-value larger than the width of the primary monitor.

So it is not necessary to have the monitor number associated with a window. It should be possible to get the location on application shutdown and set it on the next invocation of that application without reference to the monitor configuration.

Now I just have to dig through the DrRacket codebase to find the place where it launches the main window. Any clues?

I think the primary monitor has (0,0) in the upper left corner, and the other
monitors have coordinates relative to (0,0).

See get-display-left-top-inset returns non-zero offset for monitor 0 on linux · Issue #223 · racket/gui · GitHub

I am wondering what you get when you run:

(begin
  (require racket/gui)
  (define (get-display-info)
    (append (list (system-type 'os*) (system-type 'gc) (version) (get-display-count))
            (for/list ([monitor (in-range (get-display-count))])
              (let-values ([(x y) (get-display-size #:monitor monitor)]
                           [(dx dy) (get-display-left-top-inset #:monitor monitor)])
                (list
                 monitor
                 x y dx dy)))))
  (get-display-info))

A screenshot of the monitor layout might also help, if the it turns out the issues are related.

Now I just have to dig through the DrRacket codebase to find the place where it launches the main window. Any clues?

@robby will know.

The crux of the biscuit is frame:size-pref-mixin which seems to be malfunctioning on the initial frame display. It captures the old data OK but on redisplay it seems to always re-calculate the position, ignoring the old data that was previously (and correctly) saved in the relevant preference. I'm working through it now, I can demonstrate the failure but I haven't quite figured out where it's going wrong.

1 Like

It looks like you found it already and I had forgotten that it was in the framework! Here's the code, just in case: https://github.com/racket/gui/blob/master/gui-lib/framework/private/frame.rkt#L255

Thanks for looking into this! I have some vague memories triggered by looking at this code that sometimes dodgy things are happening and the code is trying to avoid doing bogus things. It may make sense to simply see what the current steps are happening when you see the bad behavior and report that here and maybe we can figure out how to change it.