X Tutup
The Wayback Machine - https://web.archive.org/web/20240302234012/https://github.com/python-xlib/python-xlib/issues/200
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating a transparent, click-through window? #200

Open
void4 opened this issue Jun 22, 2021 · 2 comments
Open

Creating a transparent, click-through window? #200

void4 opened this issue Jun 22, 2021 · 2 comments
Labels

Comments

@void4
Copy link

void4 commented Jun 22, 2021

I've seen examples for C https://stackoverflow.com/a/3646456/9779026, but is this possible with this python library as well?

I can successfully change the opacity of the entire window with

self.window.change_property(display.get_atom('_NET_WM_WINDOW_OPACITY'), Xatom.CARDINAL,32,[0x20202020])

But that isn't what I need, I need a completely transparent background on which I can draw fully opaque shapes.

Could someone please help?

Edit: Regarding the transparency, https://raw.githubusercontent.com/python-xlib/python-xlib/master/examples/shapewin.py seems to be a working example, although I do not understand it yet.

So remains my question on how to make the window completely transparent to user input (perhaps except closing the window)

@allfro
Copy link
Contributor

allfro commented May 11, 2022

@void4 here's an example that draws a red rectangle on an arbitrary part of the screen using python-xlib and ewmh to keep the window always on top:

#!/usr/bin/python

from Xlib import X, Xutil
from Xlib.ext import shape
from ewmh import EWMH


class OutlineWindow:
    def __init__(self, display, x, y, w, h, lw=3):
        self.d = display

        self.screen = self.d.screen()

        self.WM_DELETE_WINDOW = self.d.intern_atom('WM_DELETE_WINDOW')
        self.WM_PROTOCOLS = self.d.intern_atom('WM_PROTOCOLS')

        # Creates a pixel map that will be used to draw the areas that aren't masked
        bgpm = self.screen.root.create_pixmap(1, 1, self.screen.root_depth)

        # In my case I chose the color of the rectangle to be red.
        bggc = self.screen.root.create_gc(
            foreground=0xff0000,
            background=self.screen.black_pixel
        )

        # we fill the pixel map with red 
        bgpm.fill_rectangle(bggc, 0, 0, 1, 1)
        geometry = self.screen.root.get_geometry()

        # We then create a window with the background pixel map from above (a red window)
        self.window = self.screen.root.create_window(
            0, 0, geometry.width, geometry.height, 0,
            self.screen.root_depth,
            X.InputOutput,
            X.CopyFromParent,
            background_pixmap=bgpm,
            event_mask=X.StructureNotifyMask,
            colormap=X.CopyFromParent,
        )

        # We want to make sure we're notified of window destruction so we need to enable this protocol
        self.window.set_wm_protocols([self.WM_DELETE_WINDOW])
        self.window.set_wm_hints(flags=Xutil.StateHint, initial_state=Xutil.NormalState)

        # Create an outer rectangle that will be the outer edge of the visible rectangle
        outer_rect = self.window.create_pixmap(w, h, 1)
        gc = outer_rect.create_gc(foreground=1, background=0)
        # coordinates within the graphical context are always relative to itself - not the screen!
        outer_rect.fill_rectangle(gc, 0, 0, w, h)
        gc.free()

        # Create an inner rectangle that is slightly smaller to represent the inner edge of the rectangle
        inner_rect = self.window.create_pixmap(w - (lw * 2), h - (lw * 2), 1)
        gc = inner_rect.create_gc(foreground=1, background=0)
        inner_rect.fill_rectangle(gc, 0, 0, w - (lw * 2), h - (lw * 2))
        gc.free()

        # First add the outer rectangle within the window at x y coordinates
        self.window.shape_mask(shape.SO.Set, shape.SK.Bounding, x, y, outer_rect)

        # Now subtract the inner rectangle at the same coordinates + line width from the outer rect
        # This creates a red rectangular outline that can be clicked through
        self.window.shape_mask(shape.SO.Subtract, shape.SK.Bounding, x + lw, y + lw, inner_rect)
        self.window.shape_select_input(0)
        self.window.map()

        # use the python-ewmh lib to set extended attributes on the window. Make sure to do this after
        # calling window.map() otherwise your attributes will not be received by the window.
        self.ewmh = EWMH(display, self.screen.root)
        # Always on top
        self.ewmh.setWmState(self.window, 1, '_NET_WM_STATE_ABOVE')
        # Draw even over the task bar
        self.ewmh.setWmState(self.window, 1, '_NET_WM_STATE_FULLSCREEN')
        # Don't show the icon in the task bar
        self.ewmh.setWmState(self.window, 1, '_NET_WM_STATE_SKIP_TASKBAR')

        # Apply changes
        display.flush()

    # Main loop, handling events
    def loop(self):
        while True:
            e = self.d.next_event()

            # Window has been destroyed, quit
            if e.type == X.DestroyNotify:
                break

            # Somebody wants to tell us something
            elif e.type == X.ClientMessage:
                if e.client_type == self.WM_PROTOCOLS:
                    fmt, data = e.data
                    if fmt == 32 and data[0] == self.WM_DELETE_WINDOW:
                        break

if __name__ == '__main__':
    OutlineWindow(display.Display(), 0, 0, 200, 200).loop()

@3b9aca07
Copy link

3b9aca07 commented May 4, 2023

On i3wm I also had to add this attribute to make it transparent and click-through:

override_redirect=True
# create_window(x, y, width, height, border_width, depth, window_class=0, visual=0, onerror=None, **keys) method of Xlib.display.Window instance
self.window = self.screen.root.create_window(
    0, # x
    0, # y
    geometry.width, # width
    geometry.height, # height
    0, # border_width
    self.screen.root_depth, # depth
    X.InputOutput, # window_class
    X.CopyFromParent, # visual
    background_pixmap=bgpm, # attr
    event_mask=X.StructureNotifyMask, # attr
    colormap=X.CopyFromParent, # attr
    override_redirect=True # attr
)

Not sure about other GUIs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants
X Tutup