Last active
September 14, 2021 16:13
-
-
Save lukestanley/cb122d01949050d0fee8bf82c1e55a16 to your computer and use it in GitHub Desktop.
Saves icons for open X windows to a folder
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
"""Saves icons for open X windows to a folder. | |
Pypanel inspired me, by showing that Python can get icons with Xlib. | |
This does that in a more simple and uses PIL to save them too :) | |
""" | |
from PIL import Image | |
from Xlib import X, display, error, Xatom | |
DIRECTORY = "/home/user/icons/" | |
d = display.Display() | |
root = d.screen().root | |
DISPLAY_ICON = d.intern_atom("_NET_WM_ICON") | |
def get_icon(window_object): | |
"""For an X Window, return largest icon as PIL image if exists""" | |
icon = None | |
# try to get the raw icon data for the window: | |
icon_data = window_object.get_full_property(DISPLAY_ICON, 0) | |
if icon_data: # if there is an icon data to be found... | |
icon_data = icon_data.value | |
""" The value is a list of numbers, from the spec: | |
"_NET_WM_ICON CARDINAL[][2+n]/32 | |
This is an array of possible icons for the client." | |
... | |
"This is an array of 32bit packed CARDINAL ARGB with high byte | |
being A, low byte being B. The first two cardinals are width, | |
height. Data is in rows, left to right and top to bottom." - | |
https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html | |
""" | |
index = 0 # the current position, of reading icon_data | |
# while there is icon data to process: | |
while index < len(icon_data): | |
# we calculate where the data is, | |
# the icon width and height are at the start: | |
width = icon_data[index] | |
index += 1 | |
height = icon_data[index] | |
index += 1 | |
# fianlly, the pixel data is at the end: | |
icon_data_end = width * height + index | |
# get the icon data: | |
icon_data_pixels = icon_data[index:icon_data_end] | |
index = icon_data_end | |
# create an image from the last icon we found: | |
pixels = icon_data_pixels.tobytes() | |
size = (width, height) | |
icon = Image.frombuffer("RGBA", size, pixels, "raw", "BGRA", 0, 1) | |
return icon | |
def get_windows(): | |
"""Returns dict of X window's with id's as the keys, | |
containing a name, object, and icon if exists""" | |
window_info = {} | |
windows = root.get_full_property( | |
d.intern_atom("_NET_CLIENT_LIST"), Xatom.WINDOW | |
).value | |
for w in windows: | |
try: | |
window = d.create_resource_object("window", w) | |
window_name = window.get_wm_name() | |
window_info[w] = dict( | |
name=window_name, window=window, icon=get_icon(window) | |
) | |
except error.BadWindow: | |
pass # Windows can be closed while looping | |
return window_info | |
def safe_filename(unsafe_filename): | |
safe_charecters = (".", "_") | |
a_little_safer_filename = unsafe_filename.replace(" ", "_") | |
return "".join( | |
c for c in a_little_safer_filename if c.isalnum() or c in safe_charecters | |
).rstrip() | |
windows = get_windows() | |
for window_id in windows: | |
window = windows[window_id] | |
if window["icon"]: | |
name = window["name"] | |
if len(name) < 1: | |
name = str(window_id) | |
window["icon"].save(f"{DIRECTORY}{safe_filename(name)}.png") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment