Draw on top of the screen using xlib - python

I want to draw some primitives on top of all windows on the screen. I've found some code in C and tried to port it to use python's xlib:
from Xlib.display import Display
from Xlib import X
from Xlib import protocol
display = Display(':0')
root = display.screen().root
gc = root.create_gc()
root.fill_rectangle(gc, 100, 100, 500, 500)
But nothing appears on the screen (however, the root window is assigned: grabbing keyboard after it works). How to do this correctly?

You can draw on root window - your code probably works, but root window may be obscured by some kind of desktop window (nautilus, kde desktop etc). Try to start X session without any programs running and you'll see updates (you can use Xephyr or Xnest for this)
Another approach would be to create transparent window, make it topmost and draw on it's surface. You'll need to propagate mouse events to underlying windows manually.
To actually draw on top of all windows you need to create simple composite manager or if there is already CM running use it's overlay window.
From composite protocol spec:
Version 0.3 of the protocol adds the Composite Overlay Window, which
provides compositing managers with a surface on which to draw without
interference. This window is always above normal windows and is always
below the screen saver window. It is an InputOutput window whose width
and height are the screen dimensions. Its visual is the root visual
and its border width is zero. Attempts to redirect it using the
composite extension are ignored. This window does not appear in the
reply of the QueryTree request. It is also an override redirect
window. These last two features make it invisible to window managers
and other X11 clients. The only way to access the XID of this window
is via the CompositeGetOverlayWindow request. Initially, the Composite
Overlay Window is unmapped.
CompositeGetOverlayWindow returns the XID of the Composite Overlay
Window. If the window has not yet been mapped, it is mapped by this
request. When all clients who have called this request have terminated
their X11 connections the window is unmapped.
Composite managers may render directly to the Composite Overlay
Window, or they may reparent other windows to be children of this
window and render to these. Multiple clients may render to the
Composite Overlay Window, create child windows of it, reshape it, and
redefine its input region, but the specific arbitration rules followed
by these clients is not defined by this specification; these policies
should be defined by the clients themselves.

Related

How to remember currently active window and then make it focused when needed?

I'm looking for the best way to remember which external app window is currently active and how to make it focused/active, when it will be needed. There might be more then one window with the same name, so saving only name will not be enough.
I'm using pyautogui, mouse and keyboard modules to do mouse and keyboard events in specific app, and I want to make sure, the app window is currently active (beacause it must be).
My platform is Window 10, 64bit.
def click_element_1():
last_mouse_xy = mouse.get_position()
mouse.release(button='left')
mouse.move(element_1_x, element_1_y)
mouse.click(button='left')
mouse.move(last_mouse_xy[0], last_mouse_xy[1])
I just want to make the app window focused (when it's not), to do the clicks in it.
I don't have any problems with automation of the process, but I'm implementing functionatlity, which will allow user to do something on other applications, when actions in the target app will be only from time to time.
Even clicking on the taskbar applicaiton icon to show it window would be enough, if only I could be sure it's inactive now (in the background), because otherwise it will minimalize it :)
Well,In windows,you can use win32gui.GetForegroundWindow() to save the hwnd of window.(Use pywin32 module).
import win32gui
window_hwnd = win32gui.GetForegroundWindow() # this will return a number(the hwnd of active window when it is running)
To make it active:
win32gui.SetForegroundWindow(window_hwnd)
If you want to get the hwnd of tkinter,you can use
int(root.frame(),16) # root is a Tk() or Toplevel()

How do I use win32gui and win32api to locate and move a window in windows, using python

This issue really arises from me not understanding what I have to pass to win32gui.EnumWindows()
http://timgolden.me.uk/pywin32-docs/win32gui__EnumWindows_meth.html
The short version of what Im trying to accomplish:
Detect a window that may be on any of 4 different monitors (my remote desktop window, not anything actually running on the remote desktop)
Move the window to a certain monitor (I can find the monitor HANDLE already)
Maximize the window
I would like to accomplish this via win32gui and win32api
I do however have a possible other method:
If anyone knows how to make pyautogui screenshot functions observe anything other than the primary display, then it would be possible to
Use pyautogui to detect the remote desktop window header (always the same, but could appear on 4 monitors, then click on it and drag to proper monitor and maximize with pyautogui.
and a third method:
Use pygetwindow to locate and bring to focus the remote desktop window, then use win32api to move that to the proper monitor. I would need a way to use win32 to get the HANDLE of the focused window.
EDIT: I was able to get WHAT I THOUGHT was the right handle using
pygetwindow.getAllTitles() to find the title of the remote desktop program, then using pygetwindow.getWindowsWithTitle('MyRemoteDesktopName - Remote Desktop Connection') since 'MyRemoteDesktopName - Remote Desktop Connection' was listed as the title before. This provided me with a handle that I used
win32gui.MoveWindow(197160, 0, 0, 1920, 1080, True) to move the window to my original screen. HOWEVER, the remote desktop bar did not move,a nd the screen, while it now fit, did not rescale the way dragging the bar to another window would have. Each of my monitors has a different size and resolution and my remote desktop auto scales to match whatever I drag the bar to. But when I use wMoveWindow, it disconnects from that bar

tkinter - full screen window on second display

I coded a simple tkinter GUI for my 3D printer. It is a fullscreen display app that cycles through images.
For each new layer, the app updates the img= parameter for a label widget
In between layers it displays a black image as a safety precaution.
Currently, the GUI runs on top of a command-line interface. As a result, I can't see the progress of the build (e.g. current layer/total layers, build time elapsed, estimated build time completion).
I'd like the app to start on the secondary monitor in fullscreen mode.
So far I've found that even if the correct XY position for the secondary monitor is specified, the --fullscreen attribute will default to the main screen. I have not been able to identify a programmatic workaround.
I can manually hack it by using the control panel to switch the secondary and primary monitors, opening the app in fullscreen, then switching the primary monitors back. But this is painful, especially in a debug scenario where the app is potentially restarted many times.

Python / Tkinter keep window in back

In Python with Tkinter, if you use the command:
`sometkapp.overrideredirect(True)`
It will make a Tkinter window that doesn't have a border from the window manager; however, at least on my windowing system, the Tkinter window then stays on top of all the other windows.
Is there a way to send a Tkinter window to the back, so that it always stays under all other open windows?
In some system window manager decides which window is on top or on bottom.
Using overrideredirect(True) you resign with its services - on some systems this meen no drawing border, no moving on top/on bottom (probably no refreshing window), no sending events (key pressed, mouse move).
I think you can do nothing with this using Tkinter or even pure Python. Maybe other module could do something.

How do I detect when the contents of an X11 window have changed?

I'm trying to write an Xvfb-to-HTML5-canvas tool that will need to know when an X11 window changes so it can send a screen update to the client. Think of it like a web-based VNC or RDP but just for X11 windows (why send the whole desktop? =).
I thought there would be a straightforward way to do this via Xlib or xcb (xpyb) but in my experiments the best I've been able to do is detect when a window is created, destroyed, or moved. That's great and all but I need to know when the contents of windows change as well (imagine sending a keystroke to an xterm and having it appear frozen until you move the window).
If someone knows of a way to tell when the contents of an X11 window have changed I'd love to hear it! I'm open to creative solutions. For example, I tried using ffmpeg to stream x11grab through a fifo with regular checks to see if anything changed but it turned out to be extremely inefficient in terms of CPU utilization (it also seems to slow the whole system down even if nothing is going on).
I also tried just grabbing 15fps worth of screenshots in a loop while checking for changes in the most efficient way I could (e.g. does this cStringIO buffer match the last one?). That also was very CPU intensive.
The ideal solution would be for me to be able to watch the file descriptor of a socket and call a handler when there's a change in the X11 window. I'm willing to settle for detecting when the whole X11 screen has a change... That'd still be better than what I've got.
Any and all help with this is appreciated!
First of all, you can actually use vnc to track changes in just one window, not whole desktop. From x11vnc documentation:
-id windowid Show the X window corresponding to "windowid" not
the entire display. New windows like popup menus,
transient toplevels, etc, may not be seen or may be
clipped. Disabling SaveUnders or BackingStore in the
X server may help show them. x11vnc may crash if the
window is initially partially obscured, changes size,
is iconified, etc. Some steps are taken to avoid this
and the -xrandr mechanism is used to track resizes. Use
xwininfo(1) to get the window id, or use "-id pick"
to have x11vnc run xwininfo(1) for you and extract
the id. The -id option is useful for exporting very
simple applications (e.g. the current view on a webcam).
-sid windowid As -id, but instead of using the window directly it
shifts a root view to it: this shows SaveUnders menus,
etc, although they will be clipped if they extend beyond
the window.
-appshare Simple application sharing based on the -id/-sid
mechanism. Every new toplevel window that the
application creates induces a new viewer window via
a reverse connection. The -id/-sid and -connect
options are required. Run 'x11vnc -appshare -help'
for more info.
If you want to code similar functionality manually you need to use damage extension.
Here is simple example in javascript using node-x11 (sorry, I'm not sure about damage extension support in python)
var x11 = require('x11');
var X = x11.createClient(function(err, display) {
X.require('damage', function(Damage) {
var damage = X.AllocID();
Damage.Create(damage, parseInt(process.argv[2]), Damage.ReportLevel.NonEmpty);
X.on('event', function(ev) {
Damage.Subtract(damage, 0, 0);
console.log("window content changed!");
});
});
});
start it with window id as command line argument and you'll be notified whenever window content is changed.

Categories