--- /dev/null
+#!/usr/bin/env python3
+"""
+ On-Screen Display Python Client Library
+ (c) 2022 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz>
+
+
+Basic usage:
+============
+
+import osd
+osd.notify("first line", "second line")
+
+Each argument is either a single string (a notification line)
+or a pair of strings ("property", "value"). For available
+properties consult OSD Daemon documentation. These arguments
+are position sensitive.
+
+Properties may also be added as named parameters. For example:
+ osd.notify("Hello world", color="red")
+
+Due to the notation of OSD parameters and Python limitations of named
+arguments, all occurrences of '_' in the argument name are be replaced by '-'.
+
+Named arguments are treated as positional arguments placed before all others,
+in unspecified relative order. This behavior was chosen as in most cases, these
+arguments will affect all notification lines. If you need more control, use the
+positional variant.
+
+Therefore, these two invocations are equivalent:
+ osd.notify("a line", outline_color="red")
+ osd.notify(("outline-color", "red"), "a line")
+
+Connection
+==========
+
+If you don't want to send the notification to the default display,
+you can create new connection class via `osd.new_connection(DISPLAY_NAME)`
+or using `osd.Display` constructor which takes an instance of `Xlib.display.Display`.
+
+The instance of `Connection` class has the same `notify` method.
+
+You can reassign a default connection into `osd.default_connection`.
+
+Errors
+======
+
+If there is a problem with connection to the X server, library raises the corresponding
+Xlib exceptions.
+
+If a message contains any forbidden characters such as new line,
+OSDArgumentError will be raised. The `notify_sanitized` method
+filters out forbidden characters, therefore it never raises OSDArgumentError.
+"""
+
+import Xlib
+from Xlib.display import Display
+import Xlib.X
+from Xlib.xobject.drawable import Window
+
+from typing import Callable, List, Tuple, Optional, Union
+
+
+class OSDArgumentError(RuntimeError):
+ pass
+
+
+class Connection():
+ """ See module documentation. """
+ display: Display
+ root_window: Window
+ osd_queue_atom: int
+
+ def __init__(self, display: Display):
+ self.display = display
+ self.root_window = self.display.screen().root
+ self.osd_queue_atom = self.display.get_atom('OSD_QUEUE')
+
+ def _send_raw(self, val: str) -> None:
+ self.root_window.change_property(
+ self.osd_queue_atom,
+ property_type=Xlib.Xatom.STRING,
+ format=8,
+ data=val.encode(),
+ mode=Xlib.X.PropModeAppend
+ )
+ self.display.flush()
+
+ def notify_with_error_handler(self, error_handler: Callable[[str, str, bool], str], *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
+ lines: List[str] = []
+
+ def add_line(key, val):
+ def remove_char(s, ch, is_key):
+ out = []
+ for i in s:
+ if i == ch:
+ out.append(error_handler(s, ch, is_key))
+ else:
+ out.append(i)
+ return "".join(out)
+
+ key = remove_char(remove_char(str(key), "\n", True), ":", True)
+ val = remove_char(str(val), "\n", False)
+
+ lines.append(f"{key}:{val}")
+
+ for key, val in kwargs.items():
+ add_line(key.replace("_", "-"), val)
+ for x in args:
+ if isinstance(x, tuple):
+ key, val = x
+ add_line(key, val)
+ else:
+ add_line("", x)
+ msg = "\n".join(lines) + "\n\n"
+ self._send_raw(msg)
+
+ def notify(self, *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
+ def error_handler(s, ch, is_key):
+ raise OSDArgumentError(f"{'Key' if is_key else 'Value'} {repr(s)} contain forbidden character {repr(ch)}.")
+ self.notify_with_error_handler(error_handler, *args, **kwargs)
+
+ def notify_sanitized(self, *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
+ def error_handler(s, ch, is_key):
+ return ""
+ self.notify_with_error_handler(error_handler, *args, **kwargs)
+
+
+def new_connection(display_name: Optional[str] = None) -> Connection:
+ """ See module documentation. """
+ return Connection(Display(display_name))
+
+
+default_connection: Optional[Connection] = None
+
+
+def _default_or_new_connection() -> Connection:
+ global default_connection
+ if default_connection is None:
+ default_connection = new_connection()
+ return default_connection
+
+
+def notify(*args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
+ """ See module documentation. """
+ _default_or_new_connection().notify(*args, **kwargs)
+
+
+def notify_sanitized(*args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
+ """ See module documentation. """
+ _default_or_new_connection().notify_sanitized(*args, **kwargs)
--- /dev/null
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
--- /dev/null
+[metadata]
+name = osd
+version = 0.0.1
+author = Jiri Kalvoda
+author_email = jirikalvoda@kam.mff.cuni.cz
+description = On-Screen Display Client
+long_description_content_type = text/plain
+classifiers =
+ Operating System :: OS Independent
+ Programming Language :: Python :: 3
+ Programming Language :: Python :: 3.7
+ Programming Language :: Python :: 3.8
+ Programming Language :: Python :: 3.9
+ Programming Language :: Python :: 3.10
+
+[options]
+packages = osd
+python_requires = >=3.7
+zip_safe = False
+install_requires =
+ argparse >= 0.21
+ typing >= 3.0
+ python-xlib
+
+[bdist_wheel]
+universal = 1
+++ /dev/null
-#!/usr/bin/env python3
-"""
- On-Screen Display Python Client Library
- (c) 2022 Jiri Kalvoda <jirikalvoda@kam.mff.cuni.cz>
-
-
-Basic usage:
-============
-
-osd.notify("first line", "second line")
-
-Each argument is either a single string (a notification line)
-or a pair of strings ("property", "value"). For available
-properties consult OSD Daemon documentation. These arguments
-are position sensitive.
-
-Properties may also be added as named parameters. For example:
- osd.notify("Hello world", color="red")
-
-Due to the notation of OSD parameters and Python limitations of named
-arguments, all occurrences of '_' in the argument name are be replaced by '-'.
-
-Named arguments are treated as positional arguments placed before all others,
-in unspecified relative order. This behavior was chosen as in most cases, these
-arguments will affect all notification lines. If you need more control, use the
-positional variant.
-
-Therefore, these two invocations are equivalent:
- osd.notify("a line", outline_color="red")
- osd.notify(("outline-color", "red"), "a line")
-
-Connection
-==========
-
-If you don't want to send the notification to the default display,
-you can create new connection class via `osd.new_connection(DISPLAY_NAME)`
-or using `osd.Display` constructor which takes an instance of `Xlib.display.Display`.
-
-The instance of `Connection` class has the same `notify` method.
-
-You can reassign a default connection into `osd.default_connection`.
-
-Errors
-======
-
-If there is a problem with connection to the X server, library raises the corresponding
-Xlib exceptions.
-
-If a message contains any forbidden characters such as new line,
-OSDArgumentError will be raised. The `notify_sanitized` method
-filters out forbidden characters, therefore it never raises OSDArgumentError.
-"""
-
-import Xlib
-from Xlib.display import Display
-import Xlib.X
-from Xlib.xobject.drawable import Window
-
-from typing import Callable, List, Tuple, Optional, Union
-
-
-class OSDArgumentError(RuntimeError):
- pass
-
-
-class Connection():
- """ See module documentation. """
- display: Display
- root_window: Window
- osd_queue_atom: int
-
- def __init__(self, display: Display):
- self.display = display
- self.root_window = self.display.screen().root
- self.osd_queue_atom = self.display.get_atom('OSD_QUEUE')
-
- def _send_raw(self, val: str) -> None:
- self.root_window.change_property(
- self.osd_queue_atom,
- property_type=Xlib.Xatom.STRING,
- format=8,
- data=val.encode(),
- mode=Xlib.X.PropModeAppend
- )
- self.display.flush()
-
- def notify_with_error_handler(self, error_handler: Callable[[str, str, bool], str], *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
- lines: List[str] = []
-
- def add_line(key, val):
- def remove_char(s, ch, is_key):
- out = []
- for i in s:
- if i == ch:
- out.append(error_handler(s, ch, is_key))
- else:
- out.append(i)
- return "".join(out)
-
- key = remove_char(remove_char(str(key), "\n", True), ":", True)
- val = remove_char(str(val), "\n", False)
-
- lines.append(f"{key}:{val}")
-
- for key, val in kwargs.items():
- add_line(key.replace("_", "-"), val)
- for x in args:
- if isinstance(x, tuple):
- key, val = x
- add_line(key, val)
- else:
- add_line("", x)
- msg = "\n".join(lines) + "\n\n"
- self._send_raw(msg)
-
- def notify(self, *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
- def error_handler(s, ch, is_key):
- raise OSDArgumentError(f"{'Key' if is_key else 'Value'} {repr(s)} contain forbidden character {repr(ch)}.")
- self.notify_with_error_handler(error_handler, *args, **kwargs)
-
- def notify_sanitized(self, *args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
- def error_handler(s, ch, is_key):
- return ""
- self.notify_with_error_handler(error_handler, *args, **kwargs)
-
-
-def new_connection(display_name: Optional[str] = None) -> Connection:
- """ See module documentation. """
- return Connection(Display(display_name))
-
-
-default_connection: Optional[Connection] = None
-
-
-def _default_or_new_connection() -> Connection:
- global default_connection
- if default_connection is None:
- default_connection = new_connection()
- return default_connection
-
-
-def notify(*args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
- """ See module documentation. """
- _default_or_new_connection().notify(*args, **kwargs)
-
-
-def notify_sanitized(*args: Union[str, Tuple[str, str]], **kwargs: str) -> None:
- """ See module documentation. """
- _default_or_new_connection().notify_sanitized(*args, **kwargs)
+++ /dev/null
-[build-system]
-requires = ["setuptools>=61.0"]
-build-backend = "setuptools.build_meta"
+++ /dev/null
-[metadata]
-name = osd
-version = 0.0.1
-author = Jiri Kalvoda
-author_email = jirikalvoda@kam.mff.cuni.cz
-description = On-Screen Disply Client
-long_description_content_type = text/plain
-classifiers =
- Operating System :: OS Independent
- Programming Language :: Python :: 3
- Programming Language :: Python :: 3.7
- Programming Language :: Python :: 3.8
- Programming Language :: Python :: 3.9
- Programming Language :: Python :: 3.10
-
-[options]
-package_dir =
- = src
-packages = osd
-python_requires = >=3.7
-zip_safe = False
-install_requires =
- argparse >= 0.21
- typing >= 3.0
-
-[options.packages.find]
-where = src
-
-[bdist_wheel]
-universal = 1
-
+++ /dev/null
-../../../python_client_lib.py
\ No newline at end of file