Python/Linux - Check if some other app is fullscreen - python

I have developed a controller for RGB LEDs on the back of my monitor, and I would like to control them so that they match the average color on the screen when I have a full screen app running, such as a movie.
I already have the whole controller up and running in the background, but I got stuck trying to figure out how to determine if there is some app running full-screen or not. How could i do it? I am using python3 on Debian testing.
Thanks a lot for any help!

I found an answer here and modified it a bit to make it more usable. Here is my code that works on gnome. You might have to adjust the escaped windows names for other gdms.
import Xlib.display
#Find out if fullscreen app is running
screen = Xlib.display.Display().screen()
root_win = screen.root
def is_fullscreen():
#cycle through all windows
for window in root_win.query_tree()._data['children']:
width = window.get_geometry()._data["width"]
height = window.get_geometry()._data["height"]
#if window is full screen, check it the window name
if width == screen.width_in_pixels and height == screen.height_in_pixels:
if window.get_wm_name() in ['Media viewer', 'mutter guard window']:
continue
#return true if window name is not one of the gnome windows
return True
#if we reach this, no fs window is open
return False

Related

pygame fullscreen on second monitor [duplicate]

I am using pygame to program a simple behavioral test. I'm running it on my macbook pro and have almost all the functionality working. However, during testing I'll have a second, external monitor that the subject sees and the laptop monitor. I'd like to have the game so up fullscreen on the external monitor and not on the laptop's monitor so that I can monitor performance. Currently, the start of the file looks something like:
#! /usr/bin/env python2.6
import pygame
import sys
stdscr = curses.initscr()
pygame.init()
screen = pygame.display.set_mode((1900, 1100), pygame.RESIZABLE)
I was thinking of starting the game in a resizable screen, but that OS X has problems resizing the window.
Pygame doesn't support two displays in a single pygame process(yet). See the question here and developer answer immediately after, where he says
Once SDL 1.3 is finished then pygame will get support for using multiple windows in the same process.
So, your options are:
Use multiple processes. Two pygame instances, each maximized on its own screen, communicating back and forth (you could use any of: the very cool python multiprocessing module, local TCP, pipes, writing/reading files, etc)
Set the same resolution on both of your displays, and create a large (wide) window that spans them with your information on one half and the user display on the other. Then manually place the window so that the user side is on their screen and yours is on the laptop screen. It's hacky, but might a better use of your time than engineering a better solution ("If it's studpid and it works, it ain't stupid" ;).
Use pyglet, which is similar to pygame and supports full screen windows: pyglet.window.Window(fullscreen=True, screens[1])
Good luck.
I do not know if you can do this in OS X, but this is worth mentioning for the Windows users out there, if you just want to have your program to run full screen on the second screen and you are on windows, just set the other screen as the main one.
The setting can be found under Rearrange Your Displays in settings.
So far for me anything that I can run on my main display can run this way, no need to change your code.
I did something silly but it works.
i get the number of monitors with get_monitors()
than i use SDL to change the pygame window's display position by adding to it the width of the smallest screen, to be sure that the window will be positionned in the second monitor.
from screeninfo import get_monitors
numberOfmonitors = 0
smallScreenWidth = 9999
for monitor in get_monitors():
#getting the smallest screen width
smallScreenWidth = min(smallScreenWidth, monitor.width)
numberOfmonitors += 1
if numberOfmonitors > 1:
x = smallScreenWidth
y = 0
#this will position the pygame window in the second monitor
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (x,y)
#you can check with a small window
#screen = pygame.display.set_mode((100,100))
#or go full screen in second monitor
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
#if you want to do other tasks on the laptop (first monitor) while the pygame window is being displayed on the second monitor, you shoudn't use fullscreen but instead get the second monitor's width and heigh using monitor.width and monitor.height, and set the display mode like
screen = pygame.display.set_mode((width,height))
display = pyglet.canvas.get_display()
display = display.get_screens()
win = pyglet.window.Window(screen=display[1])
------------------------------------------------------
screen=display[Номер монитора]
------------------------------------------------------
display = pyglet.canvas.get_display()
display = display.get_screens()
print(display) # Все мониторы которые есть

Strange sdl side-effect on unrelated windows

When playing with sdl2 via pysdl2 I noticed this strange side-effect where once the sdl script runs unrelated windows which would normally become translucent when moved do now stay opaque.
I wouldn't mind all that much if it weren't for the nagging feeling
that this indicates that I'm doing something fundamentally wrong.
Anyone able to enlighten me as to what the heck is going on here?
Here is my script:
import sdl2
import sdl2.ext as se
import time
def main():
k = 2
event_buffer = (k * sdl2.SDL_Event)()
se.init()
window = se.Window("what the ?", size=(400, 300))
window.show()
while True:
window.refresh()
time.sleep(0.01)
sdl2.SDL_PumpEvents()
sdl2.SDL_PeepEvents(event_buffer, k, sdl2.SDL_GETEVENT,
sdl2.SDL_FIRSTEVENT, sdl2.SDL_LASTEVENT)
for event in event_buffer:
if not event.type:
continue
elif event.type == sdl2.SDL_QUIT:
se.quit()
break
else:
pass
event.type = 0
else:
continue
break
if __name__ == '__main__':
main()
And here are a before and an after screen grab:
The System Settings window of my KDE 5.45.0 desktop without the sdl script running, showing the relevant setting Desktop Effects>Translucency. Notice how the window is translucent because I'm dragging it while taking the picture.
The same but with the sdl script running. Notice how the window despite my vigorously dragging it stays stubbornly opaque.
I can also reproduce this in my Ubuntu desktop with Unity, so it's definitely not a problem of your KDE desktop. I think this is a bug in pysdl2 and this solution should be a temporary workaround until it gets fixed but in the meanwhile, you can just add this inside your while loop:
window.get_surface()
The issue is already reported here: https://github.com/marcusva/py-sdl2/issues/139

pywinauto capture_as_image adds unwanted borders

I am using pywinauto to take a screenshot of a specific window.
Here is the code I use to take a capture of notepad ("Bloc-notes" in french) :
from pywinauto import Application
app = Application().connect(title_re=".*Bloc-notes")
hwin = app.top_window()
hwin.set_focus()
img = hwin.capture_as_image()
img.save('notepad_screenshot.png')
And here is the result:
The red "border" is the background of the window. How can I safely eliminate this red border?
I tried to configure Windows 10 in order not to show windows shadows (in the "visual effects settings") but it has no effect on the size of the capture.
When I look precisely on the capture, I can see that the left, bottom and right borders are 7 pixels thick. Can I reliably remove these pixels? What I mean by "reliably" is: will it always work, and work on other computers?
Any help appreciated.
Here is the solution I found.
import ctypes
from pywinauto import Application
import win32gui
app = Application().connect(title_re=".*Bloc-notes")
hwin = app.top_window()
hwin.set_focus()
window_title = hwin.window_text()
rect = ctypes.wintypes.RECT()
DWMWA_EXTENDED_FRAME_BOUNDS = 9
ctypes.windll.dwmapi.DwmGetWindowAttribute(
ctypes.wintypes.HWND(win32gui.FindWindow(None, window_title)),
ctypes.wintypes.DWORD(DWMWA_EXTENDED_FRAME_BOUNDS),
ctypes.byref(rect),
ctypes.sizeof(rect)
)
img = hwin.capture_as_image(rect)
img.save('notepad_screenshot_ok.png')
And here is the result:
It has worked on all the tests I run (different windows).
Application().connect can return a collection of windows.
Instead use app['YOUR TITLE HERE'] or use find_windows.
From there you can capture the image without those borders.
You can find more info from the docs.

Pygame display.info giving wrong resolution size

I'm building a small game with pygame. I want the window of the game to be size of the monitors resolution. My computers screen's resolution is 1920x1080 and display.info says the window size is also 1920x1080 but when I run it, it creates a window roughly one and half times the size of my screen.
import pygame, sys
def main():
#set up pygame, main clock
pygame.init()
clock = pygame.time.Clock()
#creates an object with the computers display information
#current_h, current_w gives the monitors height and width
displayInfo = pygame.display.Info()
#set up the window
windowWidth = displayInfo.current_w
windowHeight = displayInfo.current_h
window = pygame.display.set_mode ((windowWidth, windowHeight), 0, 32)
pygame.display.set_caption('game')
#gameLoop
while True:
window.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#draw the window onto the screen
pygame.display.flip()
clock.tick(60)
main()
I've been having the same problem, and I managed to find the answer and posted it here. The answer I found is as follows:
I managed to find a commit on the Pygame BitBucket page here that explains the issue and gives an example on how to fix it.
What is happening is that some display environments can be configured to stretch windows so they don't look small on high PPI (Pixels Per Inch) displays. This stretching is what causes displays on larger resolutions to display larger than they actually are.
They provide an example code on the page I linked to showing how to fix this issue.
They fix the issue by importing ctypes and calling this:
ctypes.windll.user32.SetProcessDPIAware()
They also express that this is a Windows only solution and is available within base Python since Python 2.4. Before that it will need to be installed.
With that said, to make this work, put this bit of code anywhere before pygame.display.set_mode()
import ctypes
ctypes.windll.user32.SetProcessDPIAware()
#
# # # Anywhere Before
#
pygame.display.set_mode(resolution)
I hope this helps you and anyone else who finds they have this same issue.

PySDL2: Creating a borderless window

I've been trying to find how I might create a borderless window (One not created using the typical windows border) in PySDL2.
I've looked at what resources I could find online, but haven't been able to pinpoint anything that would tell me how to accomplish this, despite it being apparently possible.
Research:
This link states that in most cases you have a border and title bar around your window, but never went into any more detail as to how to manipulate it.
I looked at some API references for SDL's Window, and did not see that borders could be manipulated at all. (Not stated that they couldn't be, just no mention)
Despite not finding anything PySDL2 related, I did find at this link that:
sdl.setWindowBordered(window, bordered)
Sets the border state of a window.
Unfortunately, I'm unable to get this to work within my simple example script.
Thanks for looking!
You need to make sure you have the flag: SDL_WINDOW_BORDERLESS.
Full example:
import sys
import sdl2.ext
sdl2.ext.init()
window = sdl2.ext.Window("Hello World!", size=(640, 480), flags=sdl2.SDL_WINDOW_BORDERLESS)
window.show()
processor = sdl2.ext.TestEventProcessor()
processor.run(window)
Modifying your script slightly we get:
import sys
import sdl2.ext
def run():
sdl2.ext.init()
W = sdl2.ext.Window("Default",size=(400,300), flags=sdl2.SDL_WINDOW_BORDERLESS)
W.show()
running = True
while running:
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
break
W.refresh()
return 0
if __name__ == "__main__":
sys.exit(run())

Categories