How to make an overlay which capture no events - linux

I would like to draw some sort of window on top of all the other windows. For example, to display some debugging infos (like conky) or things like a timer.
The main thing is that I would like to able to continue using the other windows while using it (the events go through transparently).
I've tried doing it with pygtk, pyqt and others but can't find a way to make it a real overlay with no event capture.
Is there some low-level x11 solution?

I think the Composite-extension-approach will not work when a compositing manager is running (and thus Composite's overlay window is already used).
Since you explicitly mention "no event capture":
The SHAPE extension allows to set some different shapes for a window. Version 1.1 of this extension added the "input" shape. Just setting this to an empty region should pretty much do what you want.
Some concrete example of exactly what I think you ask for can be found in Conky's source code: http://sources.debian.net/src/conky/1.10.3-1/src/x11.cc/?hl=769#L764-L781
Edit: Since you said that you didn't find anything in Gtk (well, PyGtk), here is the function that you need in Gtk: https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-input-shape-combine-region

You might need Composite extension + GetOverlayWindow request:
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.
C api : XCompositeGetOverlayWindow

PyGTK Solution:
I think the composite and shapes X extensions are sufficiently ubiquitous and shall assume here that they are active on your system. Here's PyGtk code for this:
# avoid title bar and standard window minimize, maximize, close buttons
win.set_decorated(False)
# make the window stick above all others (super button will still override it in the z-order, which is fine)
win.set_keep_above(True)
# make events pass through
region = cairo.Region(cairo.RectangleInt(0, 0, 0, 0))
my_window.input_shape_combine_region(region)
win.show_all()
# set the entire window to be semi-transparent, if we like
win.set_opacity(0.2)
Basically what this does is tell Gtk that other than pixel (0,0) the entire window my_window should not be considered part of itself in terms of event propagation. That in turn, according to my current understanding means that when the pointer moves and clicks, the events go to the underlying window under the pointer position, as if my_window was not there.
Caveat:
This does allow your overlay window being the focus window (due to user-solicited window switching or just because it pops up and gets the focus when your application starts). Which means that for example, keyboard events will still undesirably go to it up until the user has clicked through it to make it lose focus in favor of whatever window is under the cursor. I would likely use the approach described here to iron out this aspect.
If there's a different and proper approach for making a portion of the screen "display stuff but not receive events", without building an oddball window like above over it, I'm happy to learn about it.
I assume that one's particular desktop environment (gnome, unity, etc. on linux) may interfere with this solution depending on version and configuration, on some occasions.

Related

Electron: Is it possible to set the current window to be frameless?

I would like to be able to toggle between framed and frameless window in my Electron app, without needing to construct a new window. This is because this option is a different view than what would be initially loaded, therefore it would be nice if there is a way to change the current window to be frameless.
I have found window.setFullscreen() for toggling between full screen mode. I've not been able to find anything similar for frameless window. Is there any such method or workaround that I'm not seeing?
As the docs go, you enable or disable window frame at the time of creation of browser window. After that, there are no methods you can call to enable or disable frame. However, if you really really want that option, there may be a workaround. And a workaround, is well, a workaround.
Create 2 browser windows, one over the other. The first one being transparent window(with frame and click-through) and the second one being your content window(without frame).
Implement your custom solution to keep size and position of both the windows in sync. Use ipc to share data between the windows.
Toggle the visibility of the transparent browser window to show/hide frame.
Some relevant resources:
Creating frameless window : https://electronjs.org/docs/api/frameless-window#create-a-frameless-window
Creating transparent window : https://electronjs.org/docs/api/frameless-window#transparent-window

PyQt window transparent for user actions?

I'm looking for a way to make a toplevel window transparent for mouse clicks and keyboard events. So basically it has to be only visible for the user, not interfere with what else happens on the desktop. (will be transparent) I looked at various options like setting a mask, but that also makes the window disappear where the mask is set. So what I need is a mask, only for user actions, not for visibility.
I got this to work in PyGtk using input_shape_combine_mask()
which accesses x11 shape extensions. I looked for a similar function in PyQt but couldn't find it. In other posts I find it has been done in PyQt under windows. But x11 I couldn't find yet. Any suggestions?

How do I write directly to the screen?

Specifically, I want to display text and images on the monitor, on top of all other windows, but without being clickable or in any way possible to interact with - clicks on it should go straight through to whatever window is underneath.
So far, my research has led me to try and read the X documentation regarding the composite overlay window, but unfortunately I have not been able to get anywhere with it. The only resource I found that was of any help is a small nodejs library (node-x11) which unfortunately appears to have been abandoned while still incomplete, and which I was not able to get to work. Apparently there is also a python library, but that seemed to be even less complete than the nodejs on.
node-x11 author here (and it's not abandoned, I just only add functionality I need or users request, so if you missing something please fill an issue!)
You can use GetOverlayWindow from composite extension:
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.
node-x11 example:
var x11 = require('x11');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('composite', function(err, Composite) {
Composite.GetOverlayWindow(root, function(err, overlayId) {
// now you can draw on overlayId window here.
});
});
});

How can I create an X window/client that is on top of all other windows, not under WM control and has no input? (overlay, OSD)

I want to write applications (or use existing ones, that would be even more convenient) that behave like a hardware screens OSD (on screen display), only without input.
That is: A graphical output (e.g. from a GUI toolkit like Qt or Gtk) is placed on a layer where it is above even fullscreen-windows like Firefox F11 mode or a video player in fullscreen mode. That includes "above" the mouse cursor as well, so technically and graphically the mouse cursor would move below this widget.
I don't know about real fullscreen applications with SDL or OpenGL though, but this is not the requirement. If you know this as well please include it in your answer.
Real world applications are read-only overlays like a little webcam window, a TV-station like logo or premade annotations. So all in all this is meant for live presentations, streaming and recording of screencasts and tutorials with minimal post processing.
My own hacked, unsuccesful, experiments showed at least that removing this window from the WM control ( I did this by choosing a GTK popup dialog instead of a real main window) lets you position in absolute coordinates and it will ignore things like virtual desktops and workspaces, which is good, so you can switch between those and the overlay/HUD will stay in place.
Of course this cannot be done in software with the same Z-value (top/bottom windows) as the hardware screen. So technically I am talking above all other windows but below the screensaver or lock-screen layer.
+1 internet for linking to docs and giving the right keywords.
+2 internet for a working code example, language, gui-toolkit etc. doesn't matter.
You probably need composite overlay window from Composite extension - see section 3.2 "Composite Overlay Window" extension docs. (cursor is above this window)
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.
Example using node-x11:
var x11 = require('x11');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('composite', function(err, Composite) {
Composite.GetOverlayWindow(root, function(err, overlay) {
// already automatically mapped here:
//
// 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.
});
});
});

Xlib center window

I am writing a Xlib app where I want the window to be centered. I have used XMoveWindow with (desktopWidth - width) / 2, (desktopHeight - height) / 2 and it is roughly in the right place.
However the problem is that width and height are the client area, not the total area. Is there any way for me to get the total area of the window?
I need to use Xlib because I am using Glx and OpenGL. I don't want to use SDL, nor have a bulky graphics library.
There are various ways to go about this, depending on why you are doing it. The first two are "officially supported" by most window managers and described in specs, and then it descends into fragile hacks.
Semantic
The specs encourage you to use _NET_WM_WINDOW_TYPE rather than setting the position, if it makes sense to do so. See http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2507144
For example, a DIALOG type (or a window with the WM_TRANSIENT_FOR hint set) will usually be centered on its parent window or on the screen, and the _NET_WM_WINDOW_TYPE_SPLASH (splashscreen) type will usually be centered on the screen. "Usually" here means "sensible window managers probably center it, and people using weird window managers are not your problem, let them suffer."
(Another hint along the same lines, though not what you want here, is _NET_WM_STATE_FULLSCREEN, which avoids manually sizing/positioning in order to be fullscreen.)
If semantic hints work, the window manager code to handle the positioning is hopefully smarter than anything one can easily code by hand, for example it might deal with multihead setups. Setting the proper semantic type may also allow the WM to be smart in other ways, beyond positioning.
Gravity
If there's no semantic hint in the specs that helps you, then you can center by hand. It's important to note that window managers are allowed to ignore a manual position request and some of them will. Some may only honor the request if you set the USPosition flag in WM_NORMAL_HINTS (this flag is supposed to be set only if the user explicitly requested the position, for example with a -geometry command line option). Others may ignore the request always. But, you can probably ignore WMs that do this; the user chose to use that WM.
The way you compensate for the window decorations (the titlebar, etc.) is to use the win_gravity field of WM_NORMAL_HINTS, which is originally in the ICCCM (see http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.3) but better-specified in an implementation note in the EWMH: http://standards.freedesktop.org/wm-spec/latest/ar01s09.html#id2570420
For WM_NORMAL_HINTS see http://tronche.com/gui/x/xlib/ICC/client-to-window-manager/wm-normal-hints.html#XSizeHints (note: the type of the property is WM_SIZE_HINTS and the name of the property is WM_NORMAL_HINTS, so there are two different atom names involved).
To center, you would set the win_gravity to Center, which allows you to position the center of the window (including its decorations) instead of the top-left corner.
win_gravity is not often used and is likely to be buggy in some window managers because nobody bothered to code/test it, but it should work in the more mainstream ones.
Update, possible confusion point: There are other "gravities" in the X protocol, specifically the CreateWindow request lets you set a "bit_gravity" and "win_gravity"; these are different from the XSizeHints.win_gravity. The CreateWindow gravities describe how the contents (pixels/subwindows) of a window are handled when the window is resized.
Hacks based on guessing decoration size
It's a fragile hack, but... you can try to figure out the decoration size and then incorporate that into your positioning.
To get the size of the window decorations, one way is the _NET_FRAME_EXTENTS hint, see http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2569862
For older-school window managers (but not the fancy new compositing ones, though those hopefully support _NET_FRAME_EXTENTS) the window decorations are an X window, so you can get your parent window and look at its size.
The problem with both of these approaches is that you have to map the window before the decorations are added, so you have to map; wait to get the MapNotify event; then get the decoration size; then move the window. This will unfortunately cause user-visible flicker (the window will initially appear and then move). I don't think there's a way to get the window decoration size without mapping first.
Descending further into the realm of awful hacks, you could assume that for windows after the first one you map, the decorations will match previously-mapped windows. (Not that this is a sound assumption: different kinds of windows may have different decorations.)
Implementation note: keep in mind that the decoration window can be destroyed at any time, which would cause an X error in any outstanding Xlib requests you have that mention that window and by default exit your program. To avoid this, set the X error handler when touching windows that don't belong to your client.
Override redirect
Using override redirect is a kind of bazooka with bad side effects, and not at all a good idea if your goal is just to center a window.
If you set the override redirect flag when creating a window, then the window manager won't manage its size, position, stacking order, decorations, or map state (the window manager's redirection of ConfigureRequest and MapRequest is overridden).
This is a really bad idea for anything the user would think of as a window. It's usually used for tooltips and popup menus. If you set override redirect on a window, then all the normal window management UI will be broken, the stacking order will end up basically random (the window will tend to get stuck on top or on bottom, or worse get in an infinite-loop restack fight with another client).
But, the override-redirected window won't have decorations or be touched by the WM, so you can surefire center it with no interference.
(If you just want no decorations, use a semantic type like SPLASH or use the "MWM" hints, don't use override redirect.)
Summary
The short answer is set the semantic hint if any is applicable, and otherwise use XSizeHints.win_gravity=Center.
You can kind of see why people use toolkits and SDL ;-) lots of weird historical baggage and corner cases in the client-to-window-manager interaction generally, setting window positions is just the beginning of the excitement!
win_gravity is not often used and is likely to be buggy in some window managers because nobody bothered to code/test it, but it should work in the more mainstream ones.
Apparently Unity haven't implemented this. Testing shows that XCB_GRAVITY_STATIC is not respected and by taking a quick look at Unity source code I could not find code implementing this part of the specification.

Resources