Skip to content

Instantly share code, notes, and snippets.

@dharmx
Created August 18, 2023 12:11
Show Gist options
  • Select an option

  • Save dharmx/28feb1017cae6bf5a6af26b13f097639 to your computer and use it in GitHub Desktop.

Select an option

Save dharmx/28feb1017cae6bf5a6af26b13f097639 to your computer and use it in GitHub Desktop.
A python script for making a dock in Eww.
#!/usr/bin/env python
import json
from pathlib import Path
from sys import stdout
from typing import Any, Callable, Dict, List
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Wnck", "3.0")
gi.require_version('GdkPixbuf', '2.0')
from gi.repository import GdkPixbuf, Gio, Gtk, Wnck
def desktop_data(filepath: str) -> dict:
"""
Get the Terminal, Exec and Icon entries from a .desktop file.
"""
path = Path(filepath)
if not path.exists():
return
# parse the desktop file
desktop = Gio.DesktopAppInfo.new_from_filename(filepath)
return {
"Exec": desktop.get_string("Exec"),
"Icon": desktop.get_string("Icon"),
"Terminal": desktop.get_boolean("Terminal"),
}
class IconFactory:
def __init__(self, icon_theme = Gtk.IconTheme.get_default()):
self.icon_theme = icon_theme
self.icon_size = 512
def __getattr__(self, icon_name: str):
icon_name = icon_name.replace("_", "-")
icon = self.icon_theme.lookup_icon(icon_name, self.icon_size, 0)
if not icon:
icon = self.icon_theme.lookup_icon("folder", self.icon_size, 0)
return icon.get_filename()
def generate_desktop(window: List[Dict[str, Any]], directory: str = "./applications") -> int:
directory: Path = Path(directory)
if not directory.is_dir():
directory.mkdir(parents=True)
desktop_entry = {
"Type": "Application",
"Exec": window["class_group_name"].lower(),
"Icon": window["icon_path"],
"Terminal": False,
"Name": window["class_group_name"],
"GenericName": window["class_group_name"],
}
desktop = ["[Desktop Entry]"]
desktop.extend(f"{key}={value}" for key, value in desktop_entry.items() if value)
return (directory / f"{window['class_group_name']}.desktop").write_text("\n".join(desktop))
def load_icons(icons_directory: str = "./icons"):
pass # enough coding :zzz:
def save_icon(class_group_name: str, icon: GdkPixbuf.Pixbuf, directory: str = "./icons") -> str | None:
directory: Path = Path(directory)
if not directory.is_dir():
directory.mkdir(parents=True)
icon_cache_path = directory / f"{class_group_name}.png"
if not icon_cache_path.exists():
icon.savev(str(icon_cache_path.absolute()), "png")
return str(icon_cache_path.absolute())
WindowCallable = Callable[[Wnck.Screen, Wnck.Window | None], None]
WindowCallableAction = Callable[[str, Wnck.Screen, Wnck.Window | None], WindowCallable]
CacheCallable = Callable[[GdkPixbuf.Pixbuf], None]
TWindow = Dict[str, List | int | float | str]
TWindows = List[Dict[str, Any]]
TWindowCallable = Callable[[TWindows], None]
def pretty_window(window: Wnck.Window, icons: IconFactory = IconFactory(), cache: CacheCallable = save_icon) -> TWindow:
if not window:
return None
class_group_name = window.get_class_group_name()
return {
"client_window_geometry": window.get_client_window_geometry(),
"geometry": window.get_geometry(),
"role": window.get_role(),
"window_type": window.get_window_type(),
"name": window.get_name(),
"icon_name": window.get_icon_name(),
"pid": window.get_pid(),
"xid": window.get_xid(),
"geometry": window.get_geometry(),
"icon": cache(class_group_name, window.get_icon()),
"active": window.is_active(),
"icon_path": getattr(icons, class_group_name),
"class_group_name": class_group_name,
"class_instance_name": window.get_class_instance_name(),
}
def get_windows(
screen: Wnck.Screen = Wnck.Screen.get_default(),
icons: IconFactory = IconFactory(),
on_window: TWindowCallable = generate_desktop,
cache: CacheCallable = save_icon
) -> TWindows:
while Gtk.events_pending():
Gtk.main_iteration()
windows = []
icons = IconFactory()
for window in screen.get_windows():
window_data = pretty_window(window, icons, cache)
windows.append(window_data)
on_window(window_data)
return windows
def screen_listen(
screen: Wnck.Screen = Wnck.Screen.get_default(),
on_open: WindowCallable = print,
on_close: WindowCallable = print,
on_focus: WindowCallable = print
):
def wrap_action(action: str, callback: WindowCallableAction) -> WindowCallable:
return lambda screen, window: callback(action, screen, window)
if on_open:
screen.connect("window-opened", wrap_action("window-opened", on_open))
if on_close:
screen.connect("window-closed", wrap_action("window-closed", on_close))
if on_focus:
screen.connect("active-window-changed", wrap_action("active-window-changed", on_close))
Gtk.main()
if __name__ == "__main__":
# Usage #1
# def floshed(action, _, window):
# data = pretty_window(window) or {}
# data["action"] = action
# print(json.dumps(data))
# stdout.flush()
# screen_listen(on_close=floshed, on_focus=floshed, on_open=floshed)
# Usage #2
print(json.dumps(get_windows()))
# Usage #3
# def floshed(action, screen, _):
# print(json.dumps({ "windows": get_windows(screen), "action": action }))
# stdout.flush()
# screen_listen(on_close=floshed, on_focus=floshed, on_open=floshed)
@baiyuechuu
Copy link
Copy Markdown

how to use it in eww?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment