Created
May 22, 2022 10:53
-
-
Save trappedinspacetime/e31822c75c5339bd0622db2001060857 to your computer and use it in GitHub Desktop.
drag transparent image
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# taken from https://github.com/s-zeid/bin/blob/main/display-transparent | |
"""Displays an image without a window border or background. | |
Based on code from http://bit.ly/qfvule | |
""" | |
import argparse | |
import os | |
import sys | |
from collections import namedtuple | |
import gi # apt install python3-gi | |
gi.require_version("cairo", "1.0") # apt install python3-gi-cairo | |
from gi.repository import cairo | |
gi.require_version("Gtk", "3.0") # apt install gir1.2-gtk-3.0 | |
from gi.repository import Gtk as gtk | |
gi.require_version("Gdk", "3.0") # same Debian package as for GTK+ 3 | |
from gi.repository import Gdk as gdk | |
from gi.repository import GdkPixbuf as gdk_pixbuf | |
Padding = namedtuple("Padding", "top,right,bottom,left") | |
def _close_callback(window, data): | |
"""Called when the window is closed.""" | |
window.hide() | |
gtk.main_quit() | |
def _drag_callback(window, event): | |
"""Called when the window is clicked on.""" | |
window.begin_move_drag( | |
event.button, | |
int(round(event.x + window.get_window().get_root_origin()[0])), | |
int(round(event.y + window.get_window().get_root_origin()[1])), | |
event.time | |
) | |
def make_transparent(window, cr): | |
"""Makes a window transparent.""" | |
cr.set_source_rgba(0, 0, 0, 0) | |
cr.set_operator(cairo.Operator.SOURCE) | |
cr.paint() | |
cr.set_operator(cairo.Operator.OVER) | |
def set_window_position(window, x, y): | |
pos = list(window.get_position()) | |
if x is not None: | |
pos[0] = int(x) | |
if y is not None: | |
pos[1] = int(y) | |
if x is not None or y is not None: | |
window.move(*pos) | |
def display_transparent(image_filename, size_factor=1, opacity=1, | |
x=None, y=None, padding=None, nearest=False): | |
if isinstance(padding, str): | |
padding = [int(i.strip()) for i in padding.split(",")] | |
if not padding: | |
padding = [0, 0, 0, 0] | |
elif len(padding) == 1: | |
padding = padding * 4 | |
elif len(padding) == 2: | |
padding = padding * 2 | |
elif len(padding) == 3: | |
padding = [padding[0], padding[1], padding[2], padding[1]] | |
elif len(padding) > 4: | |
padding = padding[:4] | |
padding = Padding(*[int(round(i)) for i in padding]) | |
win = gtk.Window() | |
win.set_title(os.path.basename(image_filename)) | |
win.set_decorated(False) | |
win.set_resizable(False) | |
gtk.Widget.set_opacity(win, opacity) | |
# Make sure that the main loop terminates when the window is closed | |
win.connect("delete-event", _close_callback) | |
# Makes the window paintable, so we can draw directly on it | |
win.set_app_paintable(True) | |
# This sets the windows colormap, so it supports transparency. | |
# This will only work if the wm support alpha channel | |
screen = win.get_screen() | |
rgba = screen.get_rgba_visual() | |
win.set_visual(rgba) | |
# This will actually make the window transparent. | |
#win.connect("draw", make_transparent) | |
# Load and scale the image | |
pixbuf = gdk_pixbuf.Pixbuf.new_from_file(image_filename) | |
if size_factor != 1: | |
pixbuf = pixbuf.scale_simple( | |
int(round(pixbuf.get_width() * size_factor)), | |
int(round(pixbuf.get_height() * size_factor)), | |
gdk_pixbuf.InterpType.BILINEAR if not nearest else gdk_pixbuf.InterpType.NEAREST, | |
) | |
# Add the image to a Fixed container for padding purposes | |
fixed = gtk.Fixed() | |
img = gtk.Image.new_from_pixbuf(pixbuf) | |
fixed.add(img) | |
fixed.move(img, padding.left, padding.top) | |
# Add the container to the window | |
width_padded = pixbuf.get_width() + padding.left + padding.right | |
height_padded = pixbuf.get_height() + padding.top + padding.bottom | |
win.set_size_request(width_padded, height_padded) | |
win.add(fixed) | |
# Make the window draggable | |
win.connect("button-press-event", _drag_callback) | |
win.add_events(gdk.EventMask.BUTTON_PRESS_MASK) | |
# Show and position window | |
win.connect("map-event", lambda widget, event: set_window_position(widget, x, y)) | |
win.show_all() | |
# Enter GTK main loop | |
gtk.main() | |
def main(argv): | |
parser = argparse.ArgumentParser( | |
prog=os.path.basename(argv[0]), | |
description="Displays an image with no background or window decorations." | |
) | |
parser.add_argument("filename", help="The image to display") | |
parser.add_argument("-s", "--size", type=float, default=100., | |
help="Desired size of the image as a percentage") | |
parser.add_argument("-n", "--nearest", action="store_true", | |
help="Use nearest neighbor sampling when scaling images" | |
" (results in a pixelated appearance when scaling up)") | |
parser.add_argument("-o", "--opacity", type=float, default=100., | |
help="Desired opacity of the image as a percentage") | |
parser.add_argument("-x", type=str, default=None, | |
help="Initial X position (default: auto)") | |
parser.add_argument("-y", type=str, default=None, | |
help="Initial X position (default: auto)") | |
parser.add_argument("-p", "--padding", default=None, | |
help="Padding (default: None; format:" | |
" {all-sides} | {top/bottom},{left/right} |" | |
" {t},{r/l},{b} | {t},{r},{b},{l})") | |
try: | |
args = parser.parse_args(argv[1:]) | |
except SystemExit as exit: | |
return exit.code | |
display_transparent( | |
args.filename, | |
size_factor=args.size * 0.01, | |
opacity=args.opacity * 0.01, | |
x=args.x, | |
y=args.y, | |
padding=args.padding, | |
nearest=args.nearest, | |
) | |
if __name__ == "__main__": | |
try: | |
sys.exit(main(sys.argv)) | |
except (KeyboardInterrupt, EOFError): | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment