Created
August 18, 2023 12:11
-
-
Save dharmx/28feb1017cae6bf5a6af26b13f097639 to your computer and use it in GitHub Desktop.
A python script for making a dock in Eww.
This file contains hidden or 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 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
how to use it in eww?