Skip to content

Commit

Permalink
did too many things to count
Browse files Browse the repository at this point in the history
  • Loading branch information
Commandcracker committed Mar 4, 2023
1 parent 0015c1a commit edb1f4c
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 100 deletions.
28 changes: 25 additions & 3 deletions display_server_interactions/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
This module initializes DSI
"""

# built-in modules
from platform import system as __system

__version__ = "0.0.dev7"
# local modules
from .exceptions import (
DisplayServerNotSupportedError as __DisplayServerNotSupportedError,
OSNotSupportedError as __OSNotSupportedError
)

__version__ = "0.0.dev8"
__author__ = "Commandcracker"

__os_name = __system().lower()

if __os_name == "linux":
from .linux import DSI
from .util import detect_linux_display_server as __detect_linux_display_server
from .util import LinuxDisplayServer as __LinuxDisplayServer
__linux_display_server = __detect_linux_display_server()

if __linux_display_server is __LinuxDisplayServer.X11:
from .linux import DSI
elif __linux_display_server is __LinuxDisplayServer.WAYLAND:
raise NotImplementedError("Wayland is not yet implemented.")
else:
raise __DisplayServerNotSupportedError(
"Your display server is not supported."
)

elif __os_name == "windows":
from .windows import DSI
Expand All @@ -18,6 +40,6 @@
raise NotImplementedError("MacOS is not yet implemented.")

else:
raise Exception("Your OS is not supported.")
raise __OSNotSupportedError("Your OS is not supported.")

__all__ = ["DSI"]
16 changes: 12 additions & 4 deletions display_server_interactions/__main__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
This is an example of DSI
"""

# local modules
from . import DSI


def main() -> None:
"""
This is an example of DSI
"""
with DSI() as dsi:
window = dsi.get_active_window()

print("Active window: ")
print("\tName: {}".format(window.name))
print("\tPID: {}".format(window.pid))
print(f"\tName: {window.name}")
print(f"\tPID: {window.pid}")
if window.xid:
print("\tXID: {}".format(window.xid))
print("\tGeometry: {}".format(window.geometry))
print(f"\tXID: {window.xid}")
print(f"\tGeometry: {window.geometry}")


if __name__ == "__main__":
Expand Down
19 changes: 15 additions & 4 deletions display_server_interactions/base.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
This module holds the main DSI class
"""


# built-in modules
from abc import ABCMeta, abstractmethod
from .window import WindowBase
from platform import system

# local modules
from .window import WindowBase

class DSIBase(object, metaclass=ABCMeta):

class DSIBase(metaclass=ABCMeta):
"""
Main DSI class
"""
@abstractmethod
def get_active_window(self) -> WindowBase:
"""
Gets the active window.
Returns None if no window is active.
"""
pass

@abstractmethod
def get_all_windows(self) -> list[WindowBase]:
"""
Returns a list of all Windows.
"""
pass

def get_window_by_pid(self, pid: int) -> WindowBase:
"""
Expand All @@ -32,6 +41,7 @@ def get_window_by_pid(self, pid: int) -> WindowBase:
for window in all_window:
if window.pid == pid:
return window
return None

def get_window_by_name(self, name: str) -> WindowBase:
"""
Expand All @@ -43,6 +53,7 @@ def get_window_by_name(self, name: str) -> WindowBase:
for window in all_window:
if window.name is not None and name in window.name:
return window
return None

@property
def platform(self) -> str:
Expand Down
30 changes: 28 additions & 2 deletions display_server_interactions/box.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,62 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
This module provides a Box class that represents a rectangle with a position and size.
"""


class Box(tuple):
"""
A Box represents a rectangle with a position and size.
"""

def __init__(self, x: int, y: int, width: int, height: int):
"""This is just here for autocompletion"""
pass

def __new__(self, x: int, y: int, width: int, height: int):
def __new__(cls, x: int, y: int, width: int, height: int):
return tuple.__new__(Box, (x, y, width, height))

@property
# pylint: disable-next=invalid-name
def x(self) -> int:
"""
Gets the x-coordinate of the box.
"""
return self[0]

@property
# pylint: disable-next=invalid-name
def y(self) -> int:
"""
Gets the y-coordinate of the box.
"""
return self[1]

@property
def width(self) -> int:
"""
Gets the width of the box.
"""
return self[2]

@property
def height(self) -> int:
"""
Gets the height of the box.
"""
return self[3]

def __repr__(self) -> str:
return f'Box(x={self.x}, y={self.y}, width={self.width}, height={self.height})'


def main() -> None:
"""
Creates and displays an example Box object.
"""
try:
# pylint: disable-next=import-outside-toplevel, redefined-builtin
from rich import print
except ImportError:
pass
Expand Down
11 changes: 10 additions & 1 deletion display_server_interactions/buttons.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

class MouseButtons(object):
"""
This module contains everything related too buttons
"""

# pylint: disable=too-few-public-methods


class MouseButtons:
"""
https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html\n
/usr/include/X11/X.h: 259-263
Expand All @@ -11,3 +18,5 @@ class MouseButtons(object):
MIDDLE = 3
FORWARD = 4
BACKWARD = 5

# pylint: enable=too-few-public-methods
12 changes: 12 additions & 0 deletions display_server_interactions/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""Exceptions for DSI."""


class DisplayServerNotSupportedError(Exception):
"""Exception raised when the display server is not supported."""


class OSNotSupportedError(Exception):
"""Exception raised when the operating system is not supported."""
26 changes: 23 additions & 3 deletions display_server_interactions/image.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# TODO: add way to get pixel from image

class Image(object):
"""
The Image module contains a class to hold the raw data of an image.
"""

from typing import Tuple


class Image:
"""
A class to that holds the raw data of an image.
Use np.array(Image) to get a numpy array of the image.
Expand All @@ -14,8 +20,9 @@ def __init__(self, data, width, height):
self.height = height

@property
def __array_interface__(self):
def __array_interface__(self) -> dict:
"""
A property method that returns an interface dictionary for the numpy array interface.
https://docs.scipy.org/doc/numpy/reference/arrays.interface.html
"""
return {
Expand All @@ -24,3 +31,16 @@ def __array_interface__(self):
"typestr": "|u1",
"data": self.data,
}

def __repr__(self) -> str:
return f"Image(width={self.width}, height={self.height})"

# pylint: disable-next=invalid-name
def get_pixel(self, x: int, y: int) -> Tuple[int, int, int, int]:
"""
This function retrieves the RGBA values of the pixel located at the specified coordinates,
and returns them as a 4-tuple integer.
"""
pixel_start_index = (y * self.width + x) * 4
pixel_data = self.data[pixel_start_index:pixel_start_index + 4]
return tuple(pixel_data)
35 changes: 17 additions & 18 deletions display_server_interactions/linux.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-

# local modules
from .base import DSIBase
from .window import WindowBase
from .image import Image
from .buttons import MouseButtons
from .box import Box

# built-in modules
from typing import Optional
import logging
import ctypes.util
from ctypes import (
Expand All @@ -29,6 +23,13 @@
_SimpleCData
)

# local modules
from .base import DSIBase
from .window import WindowBase
from .image import Image
from .buttons import MouseButtons
from .box import Box

# Setup Xlib Structures


Expand Down Expand Up @@ -202,7 +203,7 @@ def get_logger() -> logging.Logger:
# Setup Xlib Variables


class Masks(object):
class Masks:
"""
https://tronche.com/gui/x/xlib/events/mask.html\n
/usr/include/X11/X.h: 150-175
Expand Down Expand Up @@ -235,7 +236,7 @@ class Masks(object):
OwnerGrabButtonMask = 16777216


class EventTypes(object):
class EventTypes:
"""
https://tronche.com/gui/x/xlib/events/types.html\n
/usr/include/X11/X.h: 181-215
Expand Down Expand Up @@ -277,7 +278,7 @@ class EventTypes(object):
LASTEvent = 36


class KeyMasks(object):
class KeyMasks:
"""
https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html\n
/usr/include/X11/X.h: 221-228
Expand All @@ -292,12 +293,12 @@ class KeyMasks(object):
Mod5Mask = 128


class Xlib(object):
class Xlib:
def __init__(self):
# load libX11.so.6
x11 = ctypes.util.find_library("X11")
if not x11:
raise Exception("X11 library not found!")
raise FileNotFoundError("X11 library not found!")
self.xlib = ctypes.cdll.LoadLibrary(x11)

self.xlib.XSetErrorHandler(error_handler)
Expand Down Expand Up @@ -370,8 +371,7 @@ def __init__(self):
def __getattribute__(self, __name: str):
if __name in ["xlib", "display", "root_window"]:
return super().__getattribute__(__name)
else:
return self.xlib.__getattribute__(__name)
return self.xlib.__getattribute__(__name)


def get_window_property(xlib: Xlib, window_xid: int, property: str, type: _SimpleCData):
Expand Down Expand Up @@ -431,8 +431,7 @@ def name(self) -> str:
)
if name:
return name.decode('utf-8')
else:
return None
return None

@property
def pid(self) -> int:
Expand All @@ -453,7 +452,7 @@ def geometry(self) -> Box:
height=gwa.height
)

def get_image(self, geometry: Box = None) -> Image:
def get_image(self, geometry: Optional[Box] = None) -> Image:
if geometry is None:
geometry = self.geometry

Expand Down Expand Up @@ -518,7 +517,7 @@ def send_str(self, str: str) -> None:
for chr in str:
self.send_chr(chr)

def warp_pointer(self, x: int, y: int, geometry: Box = None) -> None:
def warp_pointer(self, x: int, y: int, geometry: Optional[Box] = None) -> None:
if geometry is None:
geometry = self.geometry

Expand Down
Loading

0 comments on commit edb1f4c

Please sign in to comment.