diff --git a/docs/conf.py b/docs/conf.py index 566ca287..f8f07662 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,7 +19,7 @@ html_static_path = ["_static"] html_css_files = [ - 'css/custom.css', + "css/custom.css", ] html_title = "Ignis Wiki" @@ -27,6 +27,7 @@ add_module_names = False + def get_widget_template(name): return f"""{name} {'-'*len(name)} @@ -34,6 +35,7 @@ def get_widget_template(name): .. autoclass:: ignis.widgets.Widget.{name} """ + def get_service_template(name): return f"""{name.capitalize().replace("_", "")} {'-'*len(name)} @@ -42,6 +44,7 @@ def get_service_template(name): :members: """ + def get_utils_function_template(name): return f"""{name} {'-'*len(name)} @@ -49,6 +52,7 @@ def get_utils_function_template(name): .. autofunction:: ignis.utils.Utils.{name} """ + def get_utils_class_template(name): return f"""{name} {'-'*len(name)} @@ -57,6 +61,7 @@ def get_utils_class_template(name): :members: """ + for i in ["widgets", "services", "utils"]: try: shutil.rmtree(f"{i}/generated") @@ -79,4 +84,4 @@ def get_utils_class_template(name): if not filename.startswith("__"): name = filename.replace(".py", "") with open(f"utils/generated/{name}.rst", "w") as file: - file.write(get_utils_class_template(name)) \ No newline at end of file + file.write(get_utils_class_template(name)) diff --git a/ignis/__init__.py b/ignis/__init__.py index c4186b9a..19cfb230 100644 --- a/ignis/__init__.py +++ b/ignis/__init__.py @@ -1,17 +1,17 @@ import gi from ctypes import CDLL -CDLL('libgtk4-layer-shell.so') +CDLL("libgtk4-layer-shell.so") gi.require_version("Gtk", "4.0") gi.require_version("Gdk", "4.0") -gi.require_version('Gtk4LayerShell', '1.0') +gi.require_version("Gtk4LayerShell", "1.0") gi.require_version("GdkPixbuf", "2.0") gi.require_version("GIRepository", "2.0") from gi.repository import GIRepository # noqa: E402 -GIRepository.Repository.prepend_library_path('/usr/lib/ignis') -GIRepository.Repository.prepend_search_path('/usr/lib/ignis') -GIRepository.Repository.prepend_library_path('/usr/lib/x86_64-linux-gnu/ignis') -GIRepository.Repository.prepend_search_path('/usr/lib/x86_64-linux-gnu/ignis') +GIRepository.Repository.prepend_library_path("/usr/lib/ignis") +GIRepository.Repository.prepend_search_path("/usr/lib/ignis") +GIRepository.Repository.prepend_library_path("/usr/lib/x86_64-linux-gnu/ignis") +GIRepository.Repository.prepend_search_path("/usr/lib/x86_64-linux-gnu/ignis") diff --git a/ignis/app.py b/ignis/app.py index 891b8604..61722578 100644 --- a/ignis/app.py +++ b/ignis/app.py @@ -118,7 +118,9 @@ def apply_css(self, style_path: str) -> None: """ if not os.path.exists(style_path): - raise FileNotFoundError(f"Provided style path doesn't exists: '{style_path}'") + raise FileNotFoundError( + f"Provided style path doesn't exists: '{style_path}'" + ) if style_path.endswith(".scss") or style_path.endswith(".sass"): compiled_scss = Utils.sass_compile(path=style_path) diff --git a/ignis/client.py b/ignis/client.py index 4fc2cf53..5e602303 100644 --- a/ignis/client.py +++ b/ignis/client.py @@ -1,13 +1,14 @@ from ignis.dbus import DBusProxy from ignis.utils import Utils + class IgnisClient: def __init__(self): self.__dbus = DBusProxy( name="com.github.linkfrg.ignis", object_path="/com/github/linkfrg/ignis", interface_name="com.github.linkfrg.ignis", - info=Utils.load_interface_xml("com.github.linkfrg.ignis") + info=Utils.load_interface_xml("com.github.linkfrg.ignis"), ) @property diff --git a/ignis/dbus.py b/ignis/dbus.py index 09152883..f30db369 100644 --- a/ignis/dbus.py +++ b/ignis/dbus.py @@ -3,6 +3,7 @@ from ignis.utils import Utils from ignis.gobject import IgnisGObject + class DBusService(IgnisGObject): def __init__( self, @@ -68,7 +69,6 @@ def __handle_method_call( params, invocation, ): - def callback(func: callable, unpacked_params) -> None: result = func(invocation, *unpacked_params) invocation.return_value(result) @@ -77,7 +77,9 @@ def callback(func: callable, unpacked_params) -> None: if func: # params can contain pixbuf, very large amount of data # and unpacking may take some time and block the main thread - Utils.ThreadTask(target=params.unpack, callback=lambda result: callback(func, result)) + Utils.ThreadTask( + target=params.unpack, callback=lambda result: callback(func, result) + ) def __handle_get_property(self, connection, sender, object_path, interface, value): func = self._properties.get(value, None) diff --git a/ignis/gobject.py b/ignis/gobject.py index cacee95e..035f6ea6 100644 --- a/ignis/gobject.py +++ b/ignis/gobject.py @@ -1,6 +1,7 @@ from gi.repository import GObject, GLib from typing import Union, Any, List + class Binding(GObject.Object): """ An object that describe binding. @@ -11,6 +12,7 @@ class Binding(GObject.Object): - **transform** (``GObject.Object``, optional, read-only): The function that accepts a new property value and returns the processed value. """ + def __init__( self, target: GObject.Object, target_property: str, transform: callable = None ): @@ -43,6 +45,7 @@ class IgnisGObject(GObject.Object): 2. It offers easier control over properties (without the need for the ``.props`` attribute). """ + def __init__(self): super().__init__() @@ -80,11 +83,22 @@ def set_property(self, property_name: str, value: Any) -> None: if value is None: return elif isinstance(value, Binding): - self.bind_property(source_property=property_name, target=value.target, target_property=value.target_property, transform=value.transform) + self.bind_property( + source_property=property_name, + target=value.target, + target_property=value.target_property, + transform=value.transform, + ) else: super().set_property(property_name, value) - def bind_property(self, source_property: str, target: GObject.Object, target_property: str, transform: callable = None) -> None: + def bind_property( + self, + source_property: str, + target: GObject.Object, + target_property: str, + transform: callable = None, + ) -> None: """ Bind ``source_property`` on ``self`` with ``target_property`` on ``target``. @@ -94,8 +108,9 @@ def bind_property(self, source_property: str, target: GObject.Object, target_pro target_property (``str``): the property on ``target`` to bind. transform (``callable``, optional): The function that accepts a new property value and returns the processed value. """ + def callback(*args): - value = target.get_property(target_property.replace('-', '_')) + value = target.get_property(target_property.replace("-", "_")) if transform: value = transform(value) self.set_property(source_property, value) diff --git a/ignis/main.py b/ignis/main.py index d01c5a6b..a1656b80 100644 --- a/ignis/main.py +++ b/ignis/main.py @@ -16,14 +16,17 @@ def __init__(self, name=None, commands=None, **attrs): def list_commands(self, ctx): return self.commands + def set_process_name(name): libc = ctypes.CDLL("libc.so.6") libc.prctl(15, ctypes.c_char_p(name.encode()), 0, 0, 0) + def print_version(ctx, param, value): if value: ctx.exit(print(f"Ignis {Utils.get_ignis_version()}")) + def call_client_func(name: str, *args) -> None: client = IgnisClient() if not client.has_owner: @@ -31,13 +34,29 @@ def call_client_func(name: str, *args) -> None: exit(1) getattr(client, name)(*args) + @click.group(cls=OrderedGroup) -@click.option('--version', is_flag=True, callback=print_version, expose_value=False, is_eager=True, help='Print version and exit') +@click.option( + "--version", + is_flag=True, + callback=print_version, + expose_value=False, + is_eager=True, + help="Print version and exit", +) def main(): set_process_name("ignis") + @main.command(name="init", help="Initialize Ignis") -@click.option("--config", "-c", help=f"Path to the configuration file (default: {DEFAULT_CONFIG_PATH})", default=DEFAULT_CONFIG_PATH, type=str, metavar="PATH") +@click.option( + "--config", + "-c", + help=f"Path to the configuration file (default: {DEFAULT_CONFIG_PATH})", + default=DEFAULT_CONFIG_PATH, + type=str, + metavar="PATH", +) @click.option("--debug", help="Print debug information to terminal", is_flag=True) def init(config: str, debug: bool) -> None: client = IgnisClient() @@ -46,47 +65,57 @@ def init(config: str, debug: bool) -> None: exit(1) run_server(config) + @main.command(name="open", help="Open window") @click.argument("window") def open(window: str) -> None: call_client_func("OpenWindow", window) + @main.command(name="close", help="Close window") @click.argument("window") def close(window: str) -> None: call_client_func("CloseWindow", window) + @main.command(name="toggle", help="Toggle window") @click.argument("window") def toggle(window: str) -> None: call_client_func("ToggleWindow", window) + @main.command(name="list-windows", help="List all windows") def list_windows() -> None: call_client_func("ListWindows") + @main.command(name="run-python", help="Execute inline python code") @click.argument("code") def run_python(code: str) -> None: call_client_func("RunPython", code) + @main.command(name="run-file", help="Execute python file") @click.argument("file") def run_file(file: str) -> None: call_client_func("RunFile", file) + @main.command(name="inspector", help="Open GTK Inspector") def inspector() -> None: call_client_func("Inspector") + @main.command(name="reload", help="Reload Ignis") def reload() -> None: call_client_func("Reload") + @main.command(name="quit", help="Quit Ignis") def quit() -> None: call_client_func("Quit") + def run_server(config: str) -> None: from ignis.app import app diff --git a/ignis/services/__init__.py b/ignis/services/__init__.py index d3428c1c..6db06816 100644 --- a/ignis/services/__init__.py +++ b/ignis/services/__init__.py @@ -2,6 +2,7 @@ from ignis.gobject import IgnisGObject from ignis.logging import logger + class ServiceClass: def __init__(self) -> None: self._services = { @@ -31,5 +32,4 @@ def get(self, service: str) -> IgnisGObject: logger.error(f"Service '{service}' not found!") - Service = ServiceClass() diff --git a/ignis/services/applications.py b/ignis/services/applications.py index 87d5fc6c..a07b68ec 100644 --- a/ignis/services/applications.py +++ b/ignis/services/applications.py @@ -13,6 +13,7 @@ options.create_option(name=PINNED_APPS_OPTION, default=[], exists_ok=True) + class ApplicationAction(IgnisGObject): """ Application action. @@ -21,6 +22,7 @@ class ApplicationAction(IgnisGObject): - **action** (``str``, read-only): ID of the action. - **name** (``str``, read-only): Human-readable name of the action. """ + def __init__(self, app: Gio.DesktopAppInfo, action: str): super().__init__() @@ -42,6 +44,7 @@ def launch(self) -> None: """ self._app.launch_action(self.action, None) + class Application(IgnisGObject): """ An application object. @@ -154,7 +157,7 @@ def launch(self) -> None: """ Launch the application. """ - exec_string = re.sub(r'%\S*', '', self.exec_string) + exec_string = re.sub(r"%\S*", "", self.exec_string) subprocess.Popen( exec_string, shell=True, @@ -163,6 +166,7 @@ def launch(self) -> None: stderr=subprocess.DEVNULL, ) + class ApplicationsService(IgnisGObject): """ Provides a list of applications installed on the system. diff --git a/ignis/services/audio.py b/ignis/services/audio.py index bcdf67c9..37c1d0fd 100644 --- a/ignis/services/audio.py +++ b/ignis/services/audio.py @@ -36,6 +36,7 @@ class Stream(IgnisGObject): - **volume** (``float``, read-write): Volume of the stream. - **is_default** (``bool``, read-only): Whether the stream is default. Works only for speakers and microphones. """ + __gsignals__ = { "removed": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()), } @@ -61,7 +62,8 @@ def _setup(self) -> None: "volume", ]: id_ = self._stream.connect( - f"notify::{property_name}", lambda *args, property_name=property_name: self.notify(property_name) + f"notify::{property_name}", + lambda *args, property_name=property_name: self.notify(property_name), ) self.__connection_ids.append(id_) @@ -146,10 +148,12 @@ def is_default(self) -> bool: return default_stream.get_id() == self.id + class DefaultSpeaker(Stream): """ :meta private: """ + def __init__(self, control: Gvc.MixerControl): super().__init__(control, None) @@ -160,10 +164,12 @@ def _sync(self) -> None: self._stream = stream self._setup() + class DefaultMicrophone(Stream): """ :meta private: """ + def __init__(self, control: Gvc.MixerControl): super().__init__(control, None) @@ -213,7 +219,11 @@ class AudioService(IgnisGObject): __gsignals__ = { "speaker-added": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (Stream,)), - "microphone-added": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (Stream,)), + "microphone-added": ( + GObject.SignalFlags.RUN_FIRST, + GObject.TYPE_NONE, + (Stream,), + ), "app-added": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (Stream,)), "recorder-added": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (Stream,)), } @@ -233,9 +243,12 @@ def __init__(self): self._apps = {} self._recorders = {} - - self._control.connect("default-sink-changed", lambda *args: self.__default_changed("speaker")) - self._control.connect("default-source-changed", lambda *args: self.__default_changed("microphone")) + self._control.connect( + "default-sink-changed", lambda *args: self.__default_changed("speaker") + ) + self._control.connect( + "default-source-changed", lambda *args: self.__default_changed("microphone") + ) self._control.connect("stream-added", self.__add_stream) self._control.connect("stream-removed", self.__remove_stream) diff --git a/ignis/services/fetch.py b/ignis/services/fetch.py index f71147c1..95cc4298 100644 --- a/ignis/services/fetch.py +++ b/ignis/services/fetch.py @@ -3,6 +3,7 @@ from gi.repository import GObject, Gtk, Gdk from typing import Tuple + class FetchService(IgnisGObject): """ System info service. @@ -206,4 +207,3 @@ def gtk_theme(self) -> str: @GObject.Property def icon_theme(self) -> str: return Gtk.IconTheme.get_for_display(Gdk.Display.get_default()).get_theme_name() - diff --git a/ignis/services/hyprland.py b/ignis/services/hyprland.py index 22e9f81a..c4031354 100644 --- a/ignis/services/hyprland.py +++ b/ignis/services/hyprland.py @@ -11,6 +11,7 @@ XDG_RUNTIME_DIR = os.getenv("XDG_RUNTIME_DIR") SOCKET_DIR = f"{XDG_RUNTIME_DIR}/hypr/{HYPRLAND_INSTANCE_SIGNATURE}" + class HyprlandService(IgnisGObject): """ Hyprland IPC client. @@ -38,7 +39,9 @@ class HyprlandService(IgnisGObject): def __init__(self): super().__init__() if not os.path.exists(SOCKET_DIR): - logger.critical("Hyprland IPC not found! To use the Hyprland service, ensure that you are running Hyprland.") + logger.critical( + "Hyprland IPC not found! To use the Hyprland service, ensure that you are running Hyprland." + ) exit(1) self._workspaces = [] @@ -101,7 +104,6 @@ def __sync_workspaces(self) -> None: self.notify("workspaces") self.notify("active-workspace") - def __sync_kb_layout(self) -> None: for kb in json.loads(self.send_command("j/devices"))["keyboards"]: if kb["main"]: @@ -112,7 +114,6 @@ def __sync_active_window(self) -> None: self._active_window = json.loads(self.send_command("j/activewindow")) self.notify("active_window") - def send_command(self, cmd: str) -> str: """ Send command to Hyprland IPC. @@ -147,4 +148,3 @@ def switch_to_workspace(self, workspace_id: int) -> None: workspace_id (``int``): ID of workspace to be switched to """ self.send_command(f"dispatch workspace {workspace_id}") - diff --git a/ignis/services/mpris.py b/ignis/services/mpris.py index a3ceef8b..2ee6db34 100644 --- a/ignis/services/mpris.py +++ b/ignis/services/mpris.py @@ -21,6 +21,7 @@ ) exit(1) + class MprisPlayer(IgnisGObject): """ A media player object. diff --git a/ignis/services/recorder.py b/ignis/services/recorder.py index d650cf13..d3606d57 100644 --- a/ignis/services/recorder.py +++ b/ignis/services/recorder.py @@ -18,11 +18,20 @@ RECORDING_DEFAULT_FILENAME_OPTION = "recording_default_filename" options.create_option(name=RECORDING_BITRATE_OPTION, default=8000, exists_ok=True) -options.create_option(name=RECORDING_DEFAULT_FILE_LOCATION_OPTION, default=GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS), exists_ok=True) -options.create_option(name=RECORDING_DEFAULT_FILENAME_OPTION, default="%Y-%m-%d_%H-%M-%S.mp4", exists_ok=True) +options.create_option( + name=RECORDING_DEFAULT_FILE_LOCATION_OPTION, + default=GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS), + exists_ok=True, +) +options.create_option( + name=RECORDING_DEFAULT_FILENAME_OPTION, + default="%Y-%m-%d_%H-%M-%S.mp4", + exists_ok=True, +) N_THREADS = str(min(max(1, GLib.get_num_processors()), 64)) + def gst_inspect(name: str) -> None: try: subprocess.run(["gst-inspect-1.0", "--exists", name], check=True) @@ -211,10 +220,14 @@ def start_recording( audio_pipeline = "" if record_microphone: - audio_pipeline = self.__combine_audio_pipeline(audio_pipeline, audio.microphone.name) + audio_pipeline = self.__combine_audio_pipeline( + audio_pipeline, audio.microphone.name + ) if record_internal_audio: - audio_pipeline = self.__combine_audio_pipeline(audio_pipeline, audio.speaker.name + ".monitor") + audio_pipeline = self.__combine_audio_pipeline( + audio_pipeline, audio.speaker.name + ".monitor" + ) if audio_devices: for device in audio_devices: diff --git a/ignis/services/system_tray.py b/ignis/services/system_tray.py index 0ac801fb..a7b29ec3 100644 --- a/ignis/services/system_tray.py +++ b/ignis/services/system_tray.py @@ -6,6 +6,7 @@ from ignis.dbus_menu import DBusMenu from ignis.logging import logger + class SystemTrayItem(IgnisGObject): """ System tray item. @@ -34,8 +35,13 @@ class SystemTrayItem(IgnisGObject): - **tooltip** (``str``, read-only): Tooltip, the text should be displayed when you hover cursor over the icon. """ + __gsignals__ = { - "ready": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()), # user shouldn't connect to this signal + "ready": ( + GObject.SignalFlags.RUN_FIRST, + GObject.TYPE_NONE, + (), + ), # user shouldn't connect to this signal "removed": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()), } @@ -61,7 +67,6 @@ def __init__(self, name: str, object_path: str): "notify::g-name-owner", lambda *args: self.emit("removed") ) - menu_path = self.__dbus.Menu if menu_path: self._menu = DBusMenu(name=self.__dbus.name, object_path=menu_path) @@ -85,7 +90,9 @@ def __init__(self, name: str, object_path: str): ]: self.__dbus.signal_subscribe( signal_name=signal_name, - callback=lambda *args, signal_name=signal_name: self.notify(signal_name.replace("New", "").lower()), + callback=lambda *args, signal_name=signal_name: self.notify( + signal_name.replace("New", "").lower() + ), ) self.__ready() diff --git a/ignis/services/wallpaper.py b/ignis/services/wallpaper.py index 39db26b7..e4abbc88 100644 --- a/ignis/services/wallpaper.py +++ b/ignis/services/wallpaper.py @@ -80,7 +80,7 @@ def __sync(self) -> None: image=CACHE_WALLPAPER_PATH, content_fit="cover", width=geometry.width, - height=geometry.height + height=geometry.height, ), ) self._windows.append(window) diff --git a/ignis/utils/exec_sh.py b/ignis/utils/exec_sh.py index b392b082..859efbf6 100644 --- a/ignis/utils/exec_sh.py +++ b/ignis/utils/exec_sh.py @@ -1,6 +1,7 @@ import subprocess from gi.repository import Gio + def exec_sh(command: str) -> subprocess.CompletedProcess: """ Execute a shell (bash) command. @@ -23,6 +24,7 @@ class AsyncCompletedProcess: - **stdout** (``str``, read-only): The output of the process. - **stderr** (``str``, read-only): The errors of the process. """ + def __init__(self, process: Gio.Subprocess) -> None: data = process.communicate(None, None) self._returncode = process.get_exit_status() @@ -43,7 +45,6 @@ def stderr(self) -> str: return self._stderr - def exec_sh_async(command: str, on_finished: callable = None) -> None: """ Execute a shell (bash) command asynchronously. @@ -53,6 +54,7 @@ def exec_sh_async(command: str, on_finished: callable = None) -> None: on_finished (``callable``, optional): A function to call when the process is finished. An instance of :class:`~ignis.utils.exec_sh.AsyncCompletedProcess` will be passed to this function. """ + def wait_check_callback(process: Gio.Subprocess, result: Gio.AsyncResult) -> None: process.wait_check_finish(result) on_finished(AsyncCompletedProcess(process)) diff --git a/ignis/utils/file_monitor.py b/ignis/utils/file_monitor.py index c9bc4287..a6b8546e 100644 --- a/ignis/utils/file_monitor.py +++ b/ignis/utils/file_monitor.py @@ -1,6 +1,7 @@ import os from gi.repository import GObject, Gio from ignis.gobject import IgnisGObject + FLAGS = { None: Gio.FileMonitorFlags.NONE, "none": Gio.FileMonitorFlags.NONE, @@ -26,6 +27,7 @@ file_monitors = [] + class FileMonitor(IgnisGObject): """ Monitor changes of the file or directory. @@ -95,7 +97,9 @@ def __init__( subdir_path = os.path.join(root, d) self.__add_submonitor(subdir_path) - file_monitors.append(self) # to prevent the garbage collector from collecting self + file_monitors.append( + self + ) # to prevent the garbage collector from collecting self def __on_change(self, file_monitor, file, other_file, event_type) -> None: path = file.get_path() diff --git a/ignis/utils/get_ignis_version.py b/ignis/utils/get_ignis_version.py index 598c8f54..a1033380 100644 --- a/ignis/utils/get_ignis_version.py +++ b/ignis/utils/get_ignis_version.py @@ -2,6 +2,7 @@ VERSION_FILE = f"{os.path.dirname(os.path.abspath(__file__))}/../VERSION" + def get_ignis_version() -> str: """ Get the current Ignis version. diff --git a/ignis/utils/get_monitor.py b/ignis/utils/get_monitor.py index 86da5f14..b678b32a 100644 --- a/ignis/utils/get_monitor.py +++ b/ignis/utils/get_monitor.py @@ -1,5 +1,6 @@ from gi.repository import Gdk + def get_monitor(monitor_id: int) -> Gdk.Monitor: """ Get the ``Gdk.Monitor`` by its ID. diff --git a/ignis/utils/get_n_monitors.py b/ignis/utils/get_n_monitors.py index c73f542c..f990d593 100644 --- a/ignis/utils/get_n_monitors.py +++ b/ignis/utils/get_n_monitors.py @@ -1,5 +1,6 @@ from gi.repository import Gdk + def get_n_monitors() -> int: """ Get the number of monitors. diff --git a/ignis/utils/get_paintable.py b/ignis/utils/get_paintable.py index dbf09b5b..093799f3 100644 --- a/ignis/utils/get_paintable.py +++ b/ignis/utils/get_paintable.py @@ -1,5 +1,6 @@ from gi.repository import Gtk, Gdk, Gio + def get_paintable(widget: Gtk.Widget, icon_name: str, size: int) -> Gdk.Paintable: """ Get a ``Gdk.Paintable`` by icon name. @@ -14,4 +15,6 @@ def get_paintable(widget: Gtk.Widget, icon_name: str, size: int) -> Gdk.Paintabl """ icon = Gio.ThemedIcon.new(icon_name) icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) - return icon_theme.lookup_by_gicon(icon, size, widget.get_scale_factor(), widget.get_direction(), 0) + return icon_theme.lookup_by_gicon( + icon, size, widget.get_scale_factor(), widget.get_direction(), 0 + ) diff --git a/ignis/utils/poll.py b/ignis/utils/poll.py index 560e36b1..ab02d47d 100644 --- a/ignis/utils/poll.py +++ b/ignis/utils/poll.py @@ -2,6 +2,7 @@ from gi.repository import GLib, GObject from typing import Any + class Poll(IgnisGObject): """ Call a callback every n seconds specefied by the timeout. @@ -22,9 +23,11 @@ class Poll(IgnisGObject): # print "Hello" every second Utils.Poll(timeout=1, callback=lambda: print("Hello")) """ + __gsignals__ = { "changed": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()), } + def __init__(self, timeout: int, callback: callable, *args): super().__init__() self.__id = None @@ -58,7 +61,7 @@ def callback(self, value: callable) -> None: def __main(self) -> None: self._output = self._callback(*self._args) self.emit("changed") - self.notify('output') + self.notify("output") self.__id = GLib.timeout_add_seconds(self._timeout, self.__main) def cancel(self) -> None: diff --git a/ignis/utils/scale_pixbuf.py b/ignis/utils/scale_pixbuf.py index 2d236abf..14c049da 100644 --- a/ignis/utils/scale_pixbuf.py +++ b/ignis/utils/scale_pixbuf.py @@ -10,6 +10,4 @@ def scale_pixbuf(pixbuf: GdkPixbuf.Pixbuf, width: int, height: int) -> GdkPixbuf width (``int``): The target width. height (``int``): The target height. """ - return pixbuf.scale_simple( - width, height, GdkPixbuf.InterpType.BILINEAR - ) + return pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR) diff --git a/ignis/utils/thread.py b/ignis/utils/thread.py index ee01e624..6d0f3a69 100644 --- a/ignis/utils/thread.py +++ b/ignis/utils/thread.py @@ -1,5 +1,6 @@ import threading + def thread(target: callable, *args, **kwargs) -> threading.Thread: """ Simply run the given function in a thread. @@ -14,10 +15,12 @@ def thread(target: callable, *args, **kwargs) -> threading.Thread: th.start() return th + def run_in_thread(func: callable) -> callable: """ Decorator to run the decorated function in a thread. """ + def wrapper(*args, **kwargs): return thread(func, *args, **kwargs) diff --git a/ignis/utils/thread_task.py b/ignis/utils/thread_task.py index cfd60e1c..a26a49d8 100644 --- a/ignis/utils/thread_task.py +++ b/ignis/utils/thread_task.py @@ -2,6 +2,7 @@ from ignis.gobject import IgnisGObject from .thread import run_in_thread + class ThreadTask(IgnisGObject): """ Execute a function in another thread and call a callback when it's finished. @@ -15,6 +16,7 @@ class ThreadTask(IgnisGObject): callback (``callabke``): The function to call when ``target`` has finished. """ + __gsignals__ = { "finished": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (object,)), } diff --git a/ignis/utils/timeout.py b/ignis/utils/timeout.py index 8425e14c..f7230a9b 100644 --- a/ignis/utils/timeout.py +++ b/ignis/utils/timeout.py @@ -1,6 +1,7 @@ from gi.repository import GLib, GObject from ignis.gobject import IgnisGObject + class Timeout(IgnisGObject): """ Call a function after a specified interval of time. @@ -17,6 +18,7 @@ class Timeout(IgnisGObject): Utils.Timeout(ms=3000, target=lambda: print("Hello")) """ + def __init__(self, ms: int, target: callable, *args): super().__init__() self._ms = ms diff --git a/ignis/widgets/__init__.py b/ignis/widgets/__init__.py index dae1432c..85442ff1 100644 --- a/ignis/widgets/__init__.py +++ b/ignis/widgets/__init__.py @@ -29,6 +29,7 @@ from .dropdown import DropDown from .overlay import Overlay + class Widget: Window = Window Label = Label diff --git a/ignis/widgets/box.py b/ignis/widgets/box.py index 25009ae9..1187525d 100644 --- a/ignis/widgets/box.py +++ b/ignis/widgets/box.py @@ -2,6 +2,7 @@ from ignis.base_widget import BaseWidget from typing import List + class Box(Gtk.Box, BaseWidget): """ Bases: `Gtk.Box `_. diff --git a/ignis/widgets/button.py b/ignis/widgets/button.py index a84a4116..3560c205 100644 --- a/ignis/widgets/button.py +++ b/ignis/widgets/button.py @@ -65,7 +65,9 @@ def on_right_click(self) -> callable: def on_right_click(self, value: callable) -> None: self._on_right_click = value if not self.__right_click_controller: - self.__right_click_controller = self.__init_controller(3, self._on_right_click) + self.__right_click_controller = self.__init_controller( + 3, self._on_right_click + ) @GObject.Property def on_middle_click(self) -> callable: @@ -75,4 +77,6 @@ def on_middle_click(self) -> callable: def on_middle_click(self, value: callable) -> None: self._on_middle_click = value if not self.__middle_click_controller: - self.__middle_click_controller = self.__init_controller(2, self._on_middle_click) + self.__middle_click_controller = self.__init_controller( + 2, self._on_middle_click + ) diff --git a/ignis/widgets/check_button.py b/ignis/widgets/check_button.py index 64fc27e0..77712d12 100644 --- a/ignis/widgets/check_button.py +++ b/ignis/widgets/check_button.py @@ -1,6 +1,7 @@ from gi.repository import Gtk, GObject from ignis.base_widget import BaseWidget + class CheckButton(Gtk.CheckButton, BaseWidget): """ Bases: `Gtk.CheckButton `_. @@ -26,6 +27,7 @@ class CheckButton(Gtk.CheckButton, BaseWidget): active=True, ) """ + __gtype_name__ = "IgnisCheckButton" __gproperties__ = {**BaseWidget.gproperties} @@ -33,7 +35,10 @@ def __init__(self, **kwargs): Gtk.CheckButton.__init__(self) BaseWidget.__init__(self, **kwargs) - self.connect('toggled', lambda x: self.on_toggled(x, x.active) if self.on_toggled else None) + self.connect( + "toggled", + lambda x: self.on_toggled(x, x.active) if self.on_toggled else None, + ) @GObject.Property def on_toggled(self) -> callable: diff --git a/ignis/widgets/entry.py b/ignis/widgets/entry.py index 6254c003..f3da4376 100644 --- a/ignis/widgets/entry.py +++ b/ignis/widgets/entry.py @@ -20,6 +20,7 @@ class Entry(Gtk.Entry, BaseWidget): on_change=lambda x: print(x.text), ) """ + __gtype_name__ = "IgnisEntry" __gproperties__ = {**BaseWidget.gproperties} @@ -29,7 +30,9 @@ def __init__(self, **kwargs): self._on_change = None BaseWidget.__init__(self, **kwargs) - self.connect("activate", lambda x: self.on_accept(x) if self.on_accept else None) + self.connect( + "activate", lambda x: self.on_accept(x) if self.on_accept else None + ) self.connect( "notify::text", lambda x, y: self.on_change(x) if self.on_change else None ) diff --git a/ignis/widgets/file_chooser_button.py b/ignis/widgets/file_chooser_button.py index fa28b2dc..a0ea3928 100644 --- a/ignis/widgets/file_chooser_button.py +++ b/ignis/widgets/file_chooser_button.py @@ -50,10 +50,7 @@ def __init__( self._dialog = dialog self._label = label - self.__file_icon = Icon( - visible=False, - style="padding-right: 7px;" - ) + self.__file_icon = Icon(visible=False, style="padding-right: 7px;") self.child = Box( child=[ diff --git a/ignis/widgets/file_dialog.py b/ignis/widgets/file_dialog.py index 3feb99f0..7abe1409 100644 --- a/ignis/widgets/file_dialog.py +++ b/ignis/widgets/file_dialog.py @@ -4,6 +4,7 @@ from ignis.widgets.file_filter import FileFilter from ignis.base_widget import BaseWidget + class FileDialog(Gtk.FileDialog, BaseWidget): """ Bases: `Gtk.FileDialog `_. @@ -59,7 +60,6 @@ def __init__(self, **kwargs): self._select_folder = False BaseWidget.__init__(self, **kwargs) - self.connect( "file-set", lambda x, file: self.on_file_set(x, file) if self.on_file_set else None, diff --git a/ignis/widgets/file_filter.py b/ignis/widgets/file_filter.py index f1be1a19..a74ef7f1 100644 --- a/ignis/widgets/file_filter.py +++ b/ignis/widgets/file_filter.py @@ -2,6 +2,7 @@ from ignis.base_widget import BaseWidget from typing import List + class FileFilter(Gtk.FileFilter, BaseWidget): """ Bases: `Gtk.FileFilter `_. diff --git a/ignis/widgets/grid.py b/ignis/widgets/grid.py index 5764b5c8..3155dfbb 100644 --- a/ignis/widgets/grid.py +++ b/ignis/widgets/grid.py @@ -2,6 +2,7 @@ from ignis.base_widget import BaseWidget from typing import List + class Grid(Gtk.Grid, BaseWidget): """ Bases: `Gtk.Grid `_. @@ -67,7 +68,6 @@ def child(self, child: List[Gtk.Widget]) -> None: self._child = child self.__apply() - def __apply(self) -> None: if self.column_num: for i, c in enumerate(self.child): diff --git a/ignis/widgets/headerbar.py b/ignis/widgets/headerbar.py index 1b8ea1cc..184c4370 100644 --- a/ignis/widgets/headerbar.py +++ b/ignis/widgets/headerbar.py @@ -1,6 +1,7 @@ from gi.repository import Gtk from ignis.base_widget import BaseWidget + class HeaderBar(Gtk.HeaderBar, BaseWidget): """ Bases: `Gtk.HeaderBar `_. diff --git a/ignis/widgets/label.py b/ignis/widgets/label.py index 7c89e30d..e6b75c74 100644 --- a/ignis/widgets/label.py +++ b/ignis/widgets/label.py @@ -1,6 +1,7 @@ from gi.repository import Gtk, Pango from ignis.base_widget import BaseWidget + class Label(Gtk.Label, BaseWidget): """ Bases: `Gtk.Label `_. diff --git a/ignis/widgets/listboxrow.py b/ignis/widgets/listboxrow.py index 7dce52b0..b2225307 100644 --- a/ignis/widgets/listboxrow.py +++ b/ignis/widgets/listboxrow.py @@ -20,6 +20,7 @@ class ListBoxRow(Gtk.ListBoxRow, BaseWidget): selected=True ) """ + __gtype_name__ = "IgnisListBoxRow" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/menuitem.py b/ignis/widgets/menuitem.py index 7ff91b99..3ae2be0a 100644 --- a/ignis/widgets/menuitem.py +++ b/ignis/widgets/menuitem.py @@ -2,6 +2,7 @@ from ignis.gobject import IgnisGObject from ignis.app import app + class MenuItem(IgnisGObject): """ Bases: :class:``ignis.gobject.IgnisGObject``. @@ -28,8 +29,16 @@ class MenuItem(IgnisGObject): submenu=Widget.PopoverMenu() ) """ + __gtype_name__ = "IgnisMenuItem" - def __init__(self, label: str, enabled: bool = True, on_activate: callable = None, submenu: Gtk.PopoverMenu = None): + + def __init__( + self, + label: str, + enabled: bool = True, + on_activate: callable = None, + submenu: Gtk.PopoverMenu = None, + ): super().__init__() self._label = label self._enabled = enabled diff --git a/ignis/widgets/overlay.py b/ignis/widgets/overlay.py index d5b2644e..b3898d4e 100644 --- a/ignis/widgets/overlay.py +++ b/ignis/widgets/overlay.py @@ -2,6 +2,7 @@ from ignis.base_widget import BaseWidget from typing import List + class Overlay(Gtk.Overlay, BaseWidget): """ Bases: `Gtk.Overlay `_. @@ -23,6 +24,7 @@ class Overlay(Gtk.Overlay, BaseWidget): ] ) """ + __gtype_name__ = "IgnisOverlay" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/picture.py b/ignis/widgets/picture.py index b483d89e..b7d10fdd 100644 --- a/ignis/widgets/picture.py +++ b/ignis/widgets/picture.py @@ -4,6 +4,7 @@ from typing import Union from ignis.utils import Utils + class Picture(Gtk.Picture, BaseWidget): """ Bases: `Gtk.Picture `_. @@ -36,7 +37,9 @@ class Picture(Gtk.Picture, BaseWidget): __gtype_name__ = "IgnisPicture" __gproperties__ = {**BaseWidget.gproperties} - def __init__(self, content_fit: str = "contain", width: int = -1, height: int = -1, **kwargs): + def __init__( + self, content_fit: str = "contain", width: int = -1, height: int = -1, **kwargs + ): Gtk.Picture.__init__(self) self.override_enum("content_fit", Gtk.ContentFit) diff --git a/ignis/widgets/popover_menu.py b/ignis/widgets/popover_menu.py index a3d96566..ad044bca 100644 --- a/ignis/widgets/popover_menu.py +++ b/ignis/widgets/popover_menu.py @@ -3,6 +3,7 @@ from typing import List from ignis.widgets.menuitem import MenuItem + class PopoverMenu(Gtk.PopoverMenu, BaseWidget): """ Subclass of `Gtk.PopoverMenu `_ @@ -62,7 +63,6 @@ def __add_item(self, item: MenuItem) -> None: else: self._current_section.append(item.label, f"app.{item.uniq_name}") - self._menu.remove_all() for i in self._sections: self._menu.append_section(None, i) diff --git a/ignis/widgets/regular_window.py b/ignis/widgets/regular_window.py index 0693349c..8cd3f67b 100644 --- a/ignis/widgets/regular_window.py +++ b/ignis/widgets/regular_window.py @@ -21,6 +21,7 @@ class RegularWindow(Gtk.Window, BaseWidget): titlebar=Widget.HeaderBar(show_title_buttons=True), ) """ + __gtype_name__ = "IgnisRegularWindow" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/scale.py b/ignis/widgets/scale.py index 932b227f..bebe734b 100644 --- a/ignis/widgets/scale.py +++ b/ignis/widgets/scale.py @@ -1,6 +1,7 @@ from gi.repository import Gtk, GObject, Gdk from ignis.base_widget import BaseWidget + class Scale(Gtk.Scale, BaseWidget): """ Bases: `Gtk.Scale `_. @@ -30,6 +31,7 @@ class Scale(Gtk.Scale, BaseWidget): value_pos='top' ) """ + __gtype_name__ = "IgnisScale" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/scroll.py b/ignis/widgets/scroll.py index 6958345d..b02400f1 100644 --- a/ignis/widgets/scroll.py +++ b/ignis/widgets/scroll.py @@ -1,6 +1,7 @@ from gi.repository import Gtk from ignis.base_widget import BaseWidget + class Scroll(Gtk.ScrolledWindow, BaseWidget): """ Bases: `Gtk.ScrolledWindow `_. @@ -16,6 +17,7 @@ class Scroll(Gtk.ScrolledWindow, BaseWidget): ) ) """ + __gtype_name__ = "IgnisScroll" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/separator.py b/ignis/widgets/separator.py index 89c62cec..95eb01f6 100644 --- a/ignis/widgets/separator.py +++ b/ignis/widgets/separator.py @@ -1,6 +1,7 @@ from gi.repository import Gtk, GObject from ignis.base_widget import BaseWidget + class Separator(Gtk.Separator, BaseWidget): """ Bases: `Gtk.Separator `_. @@ -16,6 +17,7 @@ class Separator(Gtk.Separator, BaseWidget): vertical=False, ) """ + __gtype_name__ = "IgnisSeparator" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/spin_button.py b/ignis/widgets/spin_button.py index d54d507a..eed3eb69 100644 --- a/ignis/widgets/spin_button.py +++ b/ignis/widgets/spin_button.py @@ -1,6 +1,7 @@ from gi.repository import Gtk, GObject from ignis.base_widget import BaseWidget + class SpinButton(Gtk.SpinButton, BaseWidget): """ Bases: `Gtk.SpinButton `_. @@ -24,6 +25,7 @@ class SpinButton(Gtk.SpinButton, BaseWidget): on_change=lambda x, value: print(value) ) """ + __gtype_name__ = "IgnisSpinButton" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/switch.py b/ignis/widgets/switch.py index f7cb0a8c..13268257 100644 --- a/ignis/widgets/switch.py +++ b/ignis/widgets/switch.py @@ -2,6 +2,7 @@ from ignis.base_widget import BaseWidget from typing import Any + class Switch(Gtk.Switch, BaseWidget): """ Bases: `Gtk.Switch `_. @@ -18,6 +19,7 @@ class Switch(Gtk.Switch, BaseWidget): on_change=lambda x, active: print(active), ) """ + __gtype_name__ = "IgnisSwitch" __gproperties__ = {**BaseWidget.gproperties} diff --git a/ignis/widgets/toggle_button.py b/ignis/widgets/toggle_button.py index ea7b90bf..80d87de5 100644 --- a/ignis/widgets/toggle_button.py +++ b/ignis/widgets/toggle_button.py @@ -1,6 +1,7 @@ from gi.repository import GObject, Gtk from ignis.base_widget import BaseWidget + class ToggleButton(Gtk.ToggleButton, BaseWidget): """ Bases: `Gtk.ToggleButton `_. @@ -24,7 +25,10 @@ def __init__(self, **kwargs) -> None: Gtk.ToggleButton.__init__(self) BaseWidget.__init__(self, **kwargs) - self.connect("toggled", lambda x: self.on_toggled(self, self.active) if self.on_toggled else None) + self.connect( + "toggled", + lambda x: self.on_toggled(self, self.active) if self.on_toggled else None, + ) @GObject.Property def on_toggled(self) -> callable: diff --git a/post_install.py b/post_install.py index 3c3f5126..9d46fafc 100755 --- a/post_install.py +++ b/post_install.py @@ -6,4 +6,3 @@ install_dir = sys.argv[1] compileall.compile_dir(install_dir, force=True, quiet=1) -