Skip to content

Instantly share code, notes, and snippets.

@lukestanley
Last active September 14, 2021 16:13
Show Gist options
  • Save lukestanley/cb122d01949050d0fee8bf82c1e55a16 to your computer and use it in GitHub Desktop.
Save lukestanley/cb122d01949050d0fee8bf82c1e55a16 to your computer and use it in GitHub Desktop.
Saves icons for open X windows to a folder
"""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