psychopy icon indicating copy to clipboard operation
psychopy copied to clipboard

Unable to move the psychopy.visual.Window() to the desired display

Open maartenuni opened this issue 6 years ago • 7 comments

In previous versions of psychopy, one was able to move the window to the desired display. For the issue I would like to use the following definition for a display: A physical device used to display stimuli to the user connected via hmdi, dvi, vga cable to the computer runnning the experiment, hence with display I mean the hardware and not some software definition of a display. The term monitor is used diferently within psychopy, hence I prefer the term display for now.

My pc, has two connected Displays the next to each other. In theory one can use the screen arugment of psychopy.visual.Window(), That expects a int in the range [0, ndisplays) where in my case values 0 and 1 would be valid. 0 is my left display and 1 is the right display. For our lab it is very important to have some control at which display the stimuli are presented, since the display the experimenter is looking at is in an other room then the one the participant is looking at. Our linux distribution KUbuntu KDE 16.04 generally opens new windows at the display the mouse is located at, but some programs want more control over the newly created windows. I would like very much that a display is opened based on a configuration file and not the mouse, hence I would like to use the screen argument of the psychopy.visual.Window() function.

This works perfectly when I create a regular window, where regular means without the fullscr=True option to Window(). Once I set the fullscr option to True the window always opens at the Display where the mouse is. If I try cheating: opening the window without specifying the fullscr=True option the window opens at the desired display

my system: KUbuntu 16.04 Ubuntu with KDE desktop python version = 3.5

print (psychopy.__version__)
3.1.5

Older version of psychopy do not have this issue e.g: KUbuntu 16.04 with psychopy:

print psychopy.__version__
1.82.02.

When I use this method with psychopy 1.82.02, this wasn't a issue, then the integer value I specified to the window() function determined the resulting display of the window, and not the mouse, whereas 3.1.5, the mouse is leading, and the screen=x argument of the Window() constructor only works as long the window is not fullscreen.

I hope someone would be so kind to clarify this issue.

maartenuni avatar Oct 09 '19 11:10 maartenuni

I don't much know how to help with this - we just use whatever controls Pyglet provides us, although there is also the GLFW backend that you could try instead (winType='glfw') in case that gives better results for you.

The other workaround might be to create the window as your are doing with screen=1, fullScr=False and then set to go fullscreen after creation with win.fullScr = True

peircej avatar Oct 10 '19 11:10 peircej

Many thanks for the comment!

I'll have to give the glfw backend a shot. The other workaround doesn't work unfortunately, this was the first thing I tried. Say the mouse is at display 0, and I specify win = Window(screen=1), the window opens correctly at display 1. If I then subsequently use win.fullscr = True, the window becomes fullscreen at display 0, where the mouse was and not the desired display.

maartenuni avatar Oct 10 '19 11:10 maartenuni

Unfortunately also the 'glfw' backend does not provide any relief. There the Window(screen=0) argument is not listened to at all, neither with Window(fullscr=True) or Window(fullscr=false).

maartenuni avatar Oct 10 '19 11:10 maartenuni

Ah, OK. Actually it's interesting that you say 1.82 handled this fine. Then I suppose we could use git bisect to work out where things changed (if the issue is indeed a change in PsychoPy). I'll need to try and replicate the issue on a dev machine to test it

peircej avatar Oct 10 '19 12:10 peircej

It would be very nice if this feature could be repaired. We are investigating to use psychopy in our linguistics lab. For our speech and other linguistic stimuli we use soundproof booths in order to retain laboratory conditions. Hence, it makes no sense to sit within the same booth as our participants. Hence, our labs use one display for the experimenter outside of the booth and one for the participants inside the booth. Many other python libraries do not support multiple displays at all, hence, for us psychopy was appealing because we could choose our display with software. But then it needs to work :-)

maartenuni avatar Oct 10 '19 13:10 maartenuni

I've created a small program that tries to move a pyglet window to a different display. I used the documentation of pyglet to see how this works:

https://pyglet.readthedocs.io/en/stable/modules/window.html

The idea is to get a list of screens and use one specific screen to display the window. A screen is a XLibScreen that describes my two monitors.

my list of screens =

XlibScreen(display=<pyglet.canvas.xlib.XlibDisplay object at 0x7f4e65931c88>, x=0, y=0, width=1920, height=1080, xinerama=1) XlibScreen(display=<pyglet.canvas.xlib.XlibDisplay object at 0x7f4e65931c88>, x=1920, y=0, width=1920, height=1080, xinerama=1)

notice that they are almost identical, only the x offset for my rightmost monitor = 1920, whereas for my left monitor it is: 0.

#!/usr/bin/env python3

import pyglet
import argparse as ap
import os
import sys
import logging

# pyglet.__version__ is weird over different version of pyglet...
# print ("Pyglet.version = {}".format(pyglet.__version__))

display = pyglet.canvas.get_display()
screens = display.get_screens()

# Let's only print the screen we choose if we choose one.
#for s in screens:
#    print(s)

parser = ap.ArgumentParser(
    os.path.basename(sys.argv[0]),
    description="Small utility to display a window on a given screen"
    )

parser.add_argument(
    "-s", "--screen",
    type=int,
    help=("Specify a int in the range[0, n_displays) if < 0 the default is chosen"),
    default=-1
    )
parser.add_argument(
    "-f", "--fullscreen",
    help=("Create a fullscreen window."),
    action='store_true'
    )

args = parser.parse_args()
window = None
fullscreen = args.fullscreen
screenidx = None

if args.screen >= 0:
    screenidx = args.screen
    if screenidx >= len(screens) or screenidx < 0:
        logging.warning("Invalid display index \"{}\", choosing {} instead".format(
                screenidx,
                len(screens) -1
                )
            )
        screenidx = len(screens) - 1
    screen = screens[screenidx]
    print(screen)
    window = pyglet.window.Window(screen=screen, fullscreen=fullscreen)
else:
    window = pyglet.window.Window(fullscreen=fullscreen)

pyglet.app.run()

According the docs of pyglet if one would like to use the one specific pyglet screen, one should also specify the fullscreen=True to the pyglet.window.Window(). Although, for me it doesn't work either way. Hence, at the moment this seems to be a pyglet thing and not psychopy thing. Although it did work with a experiment I programmed for someone 1, 2 years ago. I'll try to dig in which version of pyglet I used, and that was python2 whereas I'm currently on 3.

maartenuni avatar Oct 11 '19 09:10 maartenuni

My current version of pyglet:

pip list | grep pyglet pyglet 1.3.0

I'm not using newer version of pyglet because of issue #2518 which is currently not resolved. And using the program above with pyglet-1.4.5 I'm unable to move the pyglet window to the desired display.

The version which worked for me was: python 2.7.12 psychopy 1.82.02 the pyglet version was 1.1.4

maartenuni avatar Oct 11 '19 09:10 maartenuni