diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml index 9d6cfcb..1a64630 100644 --- a/.github/workflows/pr-validation.yml +++ b/.github/workflows/pr-validation.yml @@ -81,6 +81,15 @@ jobs: make native fi + # Relays the built static libs to python-publish.yml's wheel jobs (same workflow run) so they + # don't need to rebuild ~15 native libs for yum/manylinux; those jobs only link, never build here. + - name: Upload native libraries + uses: actions/upload-artifact@v7 + with: + name: orcsome3-built-libraries + path: orcsome3_built_libraries + retention-days: 1 + - name: Validate backend stub id: stubs run: make stubs-check diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 0d5d5f9..2cc5b90 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -14,6 +14,9 @@ permissions: env: CIBW_SKIP: "*-musllinux_* *t-*" CIBW_BEFORE_BUILD: "pip install 'Cython>=3.0'" + # The manylinux container has none of the X11 dev headers orcsome3_backend.pyx needs; the static + # libs from `validate`'s native build are relayed in separately (see wheels jobs' download step). + CIBW_BEFORE_ALL_LINUX: "yum install -y libX11-devel libXext-devel libXScrnSaver-devel libXtst-devel" CIBW_ENVIRONMENT: "ORCSOME3_BUILD_JOBS=2" CIBW_TEST_SKIP: "*" @@ -32,14 +35,12 @@ jobs: with: persist-credentials: false - - name: Install build dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - git cmake autoconf automake libtool pkg-config meson ninja-build \ - libx11-dev libxss-dev libxext-dev libxtst-dev curl - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable - echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + # Static libs already built by `validate` (native, Linux glibc) — only linking happens here, + # so no cmake/meson/rust toolchain is needed in this job. + - uses: actions/download-artifact@v8 + with: + name: orcsome3-built-libraries + path: orcsome3_built_libraries - uses: pypa/cibuildwheel@v4.2.0 env: @@ -58,14 +59,31 @@ jobs: with: persist-credentials: false - - name: Install build dependencies + # setuptools>=77 (needed for the SPDX `license = "MIT"` form checked into pyproject.toml) has + # dropped Python 3.8; this job resolves an older setuptools that rejects that form outright. + # Patch just this job's checkout back to the old {file=...} form + classifier before building. + - name: Use classic license form (setuptools<77, no Python 3.8 support past that) run: | - sudo apt-get update - sudo apt-get install -y \ - git cmake autoconf automake libtool pkg-config meson ninja-build \ - libx11-dev libxss-dev libxext-dev libxtst-dev curl - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable - echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + python3 -c " + content = open('pyproject.toml').read() + content = content.replace( + 'license = \"MIT\"\nlicense-files = [\"LICENSE\"]', + 'license = {file = \"LICENSE\"}', + ) + content = content.replace( + '\"Programming Language :: Python :: 3\",\n \"Development Status :: 4 - Beta\",', + '\"Programming Language :: Python :: 3\",\n \"License :: OSI Approved :: MIT License\",\n \"Development Status :: 4 - Beta\",', + ) + open('pyproject.toml', 'w').write(content) + " + grep -A1 "^license" pyproject.toml + + # Static libs already built by `validate` (native, Linux glibc) — only linking happens here, + # so no cmake/meson/rust toolchain is needed in this job. + - uses: actions/download-artifact@v8 + with: + name: orcsome3-built-libraries + path: orcsome3_built_libraries - uses: pypa/cibuildwheel@v3.4.1 env: @@ -104,6 +122,9 @@ jobs: - wheels-cp39-plus - wheels-cp38 - build_sdist + # A real release always publishes (github.ref is the tag, e.g. refs/tags/v1.0.0, not a branch); + # a manual workflow_dispatch only publishes when run from master, not a stray feature branch. + if: github.event_name == 'release' || github.ref == 'refs/heads/master' runs-on: ubuntu-latest permissions: id-token: write @@ -111,13 +132,20 @@ jobs: name: pypi url: https://pypi.org/p/orcsome3 steps: + # Explicit names, not "download everything" — orcsome3-built-libraries (relayed to the wheel + # jobs) also exists in this run and would otherwise land in dist/ and break the publish step. - uses: actions/download-artifact@v8 with: + pattern: "wheels-*" path: dist merge-multiple: true + - uses: actions/download-artifact@v8 + with: + name: sdist + path: dist + - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist/ - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/orcsome3/aliases.py b/orcsome3/aliases.py index 4ddc309..92948df 100644 --- a/orcsome3/aliases.py +++ b/orcsome3/aliases.py @@ -1,5 +1,7 @@ """Short key names mapped to X11 keysym names (`xev` / `X11/keysymdef.h` without the `XK_` prefix).""" +from __future__ import annotations + KEYS: dict[str, str] = { "`": "grave", "-": "minus", diff --git a/orcsome3/libs/build/libraries.py b/orcsome3/libs/build/libraries.py index 6497089..8d4e8b2 100644 --- a/orcsome3/libs/build/libraries.py +++ b/orcsome3/libs/build/libraries.py @@ -8,7 +8,7 @@ import traceback import urllib.request from pathlib import Path -from typing import Any, Callable, Optional, cast +from typing import Any, Callable, List, Optional, cast from setuptools import setup from setuptools.extension import Extension @@ -841,8 +841,10 @@ def _build() -> None: def _cythonize_extensions(module_list: list[Extension], **options: Any) -> list[Extension]: + # list[...] inside cast()'s first arg is evaluated at runtime (not deferred by `from __future__ + # import annotations`, unlike real annotations); bare generics need 3.9+, so use typing.List here. cythonize: Callable[..., list[Extension]] = cast( - Callable[..., list[Extension]], + Callable[..., List[Extension]], __import__(name="Cython.Build.Dependencies", fromlist=["cythonize"]).cythonize, ) return cythonize(module_list=module_list, **options) diff --git a/orcsome3/libs/build/recipes.py b/orcsome3/libs/build/recipes.py index 532ac82..221a897 100644 --- a/orcsome3/libs/build/recipes.py +++ b/orcsome3/libs/build/recipes.py @@ -1,5 +1,7 @@ """Library source versions and declarative build recipes (used by engine.py).""" +from __future__ import annotations + from pathlib import Path from typing import Any @@ -216,7 +218,13 @@ def _recipe(name: str, **kwargs: Any) -> CMakeGitRecipe: url=LIBRARIES_SOURCES_VERSION["pixman"][0], tag=LIBRARIES_SOURCES_VERSION["pixman"][1], source_folder=versioned_folder( - name="pixman", version=LIBRARIES_SOURCES_VERSION["pixman"][1].removeprefix("pixman-") + # str.removeprefix() is 3.9+; this project targets 3.8. + name="pixman", + version=( + LIBRARIES_SOURCES_VERSION["pixman"][1][len("pixman-") :] + if LIBRARIES_SOURCES_VERSION["pixman"][1].startswith("pixman-") + else LIBRARIES_SOURCES_VERSION["pixman"][1] + ), ), pkg_config_names=["pixman-1"], include_subdirs=["include", "include/pixman-1"], diff --git a/orcsome3/libs/cython_libs/orcsome3_backend.pyx b/orcsome3/libs/cython_libs/orcsome3_backend.pyx index 3d77c63..fb7c818 100644 --- a/orcsome3/libs/cython_libs/orcsome3_backend.pyx +++ b/orcsome3/libs/cython_libs/orcsome3_backend.pyx @@ -50,6 +50,251 @@ cdef void release_icon_data(IconData *icon_data): icon_data.length = 0 icon_data.magick_memory = False + +# Enums + +class CONSTANTS(pyenum.IntEnum): + CurrentTime = xlib.CurrentTime + AnyPropertyType = xlib.AnyPropertyType + NoSymbol = xlib.NoSymbol + AnyKey = xlib.AnyKey + XkbUseCoreKbd = xlib.XkbUseCoreKbd + RevertToNone = xlib.RevertToNone + RevertToPointerRoot = xlib.RevertToPointerRoot + RevertToParent = xlib.RevertToParent + +class EVENT_TYPES(pyenum.IntEnum): + # Generic event + GenericEvent = xlib.GenericEvent + # XErrorEvent + ErrorEvent = 0 + # XKeyEvent + KeyPress = xlib.KeyPress + KeyRelease = xlib.KeyRelease + # XButtonEvent + ButtonPress = xlib.ButtonPress + ButtonRelease = xlib.ButtonRelease + # XMotionEvent + MotionNotify = xlib.MotionNotify + # XCrossingEvent + EnterNotify = xlib.EnterNotify + LeaveNotify = xlib.LeaveNotify + # XFocusChangeEvent + FocusIn = xlib.FocusIn + FocusOut = xlib.FocusOut + # XExposeEvent + Expose = xlib.Expose + # XGraphicsExposeEvent + GraphicsExpose = xlib.GraphicsExpose + # XNoExposeEvent + NoExpose = xlib.NoExpose + # XVisibilityEvent + VisibilityNotify = xlib.VisibilityNotify + # XCreateWindowEvent + CreateNotify = xlib.CreateNotify + # XDestroyWindowEvent + DestroyNotify = xlib.DestroyNotify + # XUnmapEvent + UnmapNotify = xlib.UnmapNotify + # XMapEvent + MapNotify = xlib.MapNotify + # XMapRequestEvent + MapRequest = xlib.MapRequest + # XReparentEvent + ReparentNotify = xlib.ReparentNotify + # XConfigureEvent + ConfigureNotify = xlib.ConfigureNotify + # XGravityEvent + GravityNotify = xlib.GravityNotify + # XResizeRequestEvent + ResizeRequest = xlib.ResizeRequest + # XConfigureRequestEvent + ConfigureRequest = xlib.ConfigureRequest + # XCirculateEvent + CirculateNotify = xlib.CirculateNotify + # XCirculateRequestEvent + CirculateRequest = xlib.CirculateRequest + # XPropertyEvent + PropertyNotify = xlib.PropertyNotify + # XSelectionClearEvent + SelectionClear = xlib.SelectionClear + # XSelectionRequestEvent + SelectionRequest = xlib.SelectionRequest + # XSelectionEvent + SelectionNotify = xlib.SelectionNotify + # XColormapEvent + ColormapNotify = xlib.ColormapNotify + # XClientMessageEvent + ClientMessage = xlib.ClientMessage + # XMappingEvent + MappingNotify = xlib.MappingNotify + # XKeymapEvent + KeymapNotify = xlib.KeymapNotify + +class INPUT_EVENT_MASKS(pyenum.IntEnum): + NoEventMask = xlib.NoEventMask + StructureNotifyMask = xlib.StructureNotifyMask + SubstructureNotifyMask = xlib.SubstructureNotifyMask + SubstructureRedirectMask = xlib.SubstructureRedirectMask + PropertyChangeMask = xlib.PropertyChangeMask + FocusChangeMask = xlib.FocusChangeMask + KeyPressMask = xlib.KeyPressMask + KeyReleaseMask = xlib.KeyReleaseMask + ButtonPressMask = xlib.ButtonPressMask + ButtonReleaseMask = xlib.ButtonReleaseMask + +class KEY_MASKS(pyenum.IntEnum): + AnyModifier = xlib.AnyModifier + Mod1Mask = xlib.Mod1Mask + ControlMask = xlib.ControlMask + ShiftMask = xlib.ShiftMask + Mod2Mask = xlib.Mod2Mask + Mod4Mask = xlib.Mod4Mask + LockMask = xlib.LockMask + +class BUTTON_MASKS(pyenum.IntEnum): + AnyModifier = xlib.AnyModifier + Button1Mask = xlib.Button1Mask + Button2Mask = xlib.Button2Mask + Button3Mask = xlib.Button3Mask + Button4Mask = xlib.Button4Mask + Button5Mask = xlib.Button5Mask + +class BUTTONS(pyenum.IntEnum): + AnyButton = xlib.AnyButton + Button1 = xlib.Button1 + Button2 = xlib.Button2 + Button3 = xlib.Button3 + Button4 = xlib.Button4 + Button5 = xlib.Button5 + +class GRAB_MODE(pyenum.IntEnum): + GrabModeSync = xlib.GrabModeSync + GrabModeAsync = xlib.GrabModeAsync + +class WINDOW_VALUE_MASK(pyenum.IntEnum): + CWX = xlib.CWX + CWY = xlib.CWY + CWWidth = xlib.CWWidth + CWHeight = xlib.CWHeight + CWBorderWidth = xlib.CWBorderWidth + CWSibling = xlib.CWSibling + CWStackMode = xlib.CWStackMode + +class WINDOW_STACKING_METHOD(pyenum.IntEnum): + Above = xlib.Above + Below = xlib.Below + TopIf = xlib.TopIf + BottomIf = xlib.BottomIf + Opposite = xlib.Opposite + +class SET_PROPERTY_MODE(pyenum.IntEnum): + PropModeReplace = xlib.PropModeReplace + PropModePrepend = xlib.PropModePrepend + PropModeAppend = xlib.PropModeAppend + +class WINDOW_MAP_STATE(pyenum.IntEnum): + IsUnmapped = xlib.IsUnmapped + IsUnviewable = xlib.IsUnviewable + IsViewable = xlib.IsViewable + +class SCREENSAVER_STATE(pyenum.IntEnum): + ScreenSaverOff = xlib.ScreenSaverOff + ScreenSaverOn = xlib.ScreenSaverOn + ScreenSaverCycle = xlib.ScreenSaverCycle + ScreenSaverDisabled = xlib.ScreenSaverDisabled + +class SCREENSAVER_KIND(pyenum.IntEnum): + ScreenSaverBlanked = xlib.ScreenSaverBlanked + ScreenSaverInternal = xlib.ScreenSaverInternal + ScreenSaverExternal = xlib.ScreenSaverExternal + +class KB_GROUP_INDEX(pyenum.IntEnum): + XkbGroup1Index = xlib.XkbGroup1Index + XkbGroup2Index = xlib.XkbGroup2Index + XkbGroup3Index = xlib.XkbGroup3Index + XkbGroup4Index = xlib.XkbGroup4Index + XkbAnyGroup = xlib.XkbAnyGroup + XkbAllGroups = xlib.XkbAllGroups + +class NOTIFY_MODES(pyenum.IntEnum): + NotifyNormal = xlib.NotifyNormal + NotifyGrab = xlib.NotifyGrab + NotifyUngrab = xlib.NotifyUngrab + NotifyWhileGrabbed = xlib.NotifyWhileGrabbed + +class NOTIFY_DETAILS(pyenum.IntEnum): + NotifyAncestor = xlib.NotifyAncestor + NotifyVirtual = xlib.NotifyVirtual + NotifyInferior = xlib.NotifyInferior + NotifyNonlinear = xlib.NotifyNonlinear + NotifyNonlinearVirtual = xlib.NotifyNonlinearVirtual + NotifyPointer = xlib.NotifyPointer + NotifyPointerRoot = xlib.NotifyPointerRoot + NotifyDetailNone = xlib.NotifyDetailNone + +class PROPERTY_NOTIFICATION(pyenum.IntEnum): + PropertyNewValue = xlib.PropertyNewValue + PropertyDelete = xlib.PropertyDelete + +class PROPERTY_FORMAT(pyenum.Enum): + """ + Enum representing the valid formats when getting/setting a property. + + - CHAR: Format with value 8. The value of the property is a char array + - SHORT: Format with value 16. The value of the property is a short array + - LONG: Format with value 32. The value of the property is a long array + """ + + CHAR = (8, "b") + SHORT = (16, "h") + LONG = (32, "l") + + @classmethod + def new_from_value(cls, value: Union[str, int]) -> "PROPERTY_FORMAT": + for member in cls: + if value in member.value: + return member + raise ValueError(f"The value {value} is not in the enum members") + +class DPMS_POWER_LEVEL(pyenum.IntEnum): + DPMSModeOn = xlib.DPMSModeOn + DPMSModeStandby = xlib.DPMSModeStandby + DPMSModeSuspend = xlib.DPMSModeSuspend + DPMSModeOff = xlib.DPMSModeOff + +class PYLOOP_NEW_LOOP_FLAGS(pyenum.IntEnum): + EVFLAG_AUTO = libev.EVFLAG_AUTO + EVFLAG_NOENV = libev.EVFLAG_NOENV + EVFLAG_FORKCHECK = libev.EVFLAG_FORKCHECK + EVFLAG_NOINOTIFY = libev.EVFLAG_NOINOTIFY + EVFLAG_SIGNALFD = libev.EVFLAG_SIGNALFD + EVFLAG_NOSIGMASK = libev.EVFLAG_NOSIGMASK + EVBACKEND_SELECT = libev.EVBACKEND_SELECT + EVBACKEND_POLL = libev.EVBACKEND_POLL + EVBACKEND_EPOLL = libev.EVBACKEND_EPOLL + EVBACKEND_KQUEUE = libev.EVBACKEND_KQUEUE + EVBACKEND_DEVPOLL = libev.EVBACKEND_DEVPOLL + EVBACKEND_PORT = libev.EVBACKEND_PORT + EVBACKEND_ALL = libev.EVBACKEND_ALL + EVBACKEND_MASK = libev.EVBACKEND_MASK + +class PYLOOP_RUN_LOOP_FLAGS(pyenum.IntEnum): + EVRUN_ALWAYS = 0 # Keep handling events until either no event watchers are active anymore or "ev_break" was called + EVRUN_ONCE = libev.EVRUN_ONCE + EVRUN_NOWAIT = libev.EVRUN_NOWAIT + +class PYLOOP_BREAK_LOOP_FLAGS(pyenum.IntEnum): + EVBREAK_ALL = libev.EVBREAK_ALL + EVBREAK_ONE = libev.EVBREAK_ONE + EVBREAK_CANCEL = libev.EVBREAK_CANCEL + +class PYIOWATCHER_INIT_FLAGS(pyenum.IntEnum): + EV_READ = libev.EV_READ + EV_WRITE = libev.EV_WRITE + EV_READ_WRITE = libev.EV_READ | libev.EV_WRITE + + cdef class PyDisplay: cdef xlib.Display *_display @@ -1168,250 +1413,6 @@ cdef class PyStatWatcher: ) -# Enums - -class CONSTANTS(pyenum.IntEnum): - CurrentTime = xlib.CurrentTime - AnyPropertyType = xlib.AnyPropertyType - NoSymbol = xlib.NoSymbol - AnyKey = xlib.AnyKey - XkbUseCoreKbd = xlib.XkbUseCoreKbd - RevertToNone = xlib.RevertToNone - RevertToPointerRoot = xlib.RevertToPointerRoot - RevertToParent = xlib.RevertToParent - -class EVENT_TYPES(pyenum.IntEnum): - # Generic event - GenericEvent = xlib.GenericEvent - # XErrorEvent - ErrorEvent = 0 - # XKeyEvent - KeyPress = xlib.KeyPress - KeyRelease = xlib.KeyRelease - # XButtonEvent - ButtonPress = xlib.ButtonPress - ButtonRelease = xlib.ButtonRelease - # XMotionEvent - MotionNotify = xlib.MotionNotify - # XCrossingEvent - EnterNotify = xlib.EnterNotify - LeaveNotify = xlib.LeaveNotify - # XFocusChangeEvent - FocusIn = xlib.FocusIn - FocusOut = xlib.FocusOut - # XExposeEvent - Expose = xlib.Expose - # XGraphicsExposeEvent - GraphicsExpose = xlib.GraphicsExpose - # XNoExposeEvent - NoExpose = xlib.NoExpose - # XVisibilityEvent - VisibilityNotify = xlib.VisibilityNotify - # XCreateWindowEvent - CreateNotify = xlib.CreateNotify - # XDestroyWindowEvent - DestroyNotify = xlib.DestroyNotify - # XUnmapEvent - UnmapNotify = xlib.UnmapNotify - # XMapEvent - MapNotify = xlib.MapNotify - # XMapRequestEvent - MapRequest = xlib.MapRequest - # XReparentEvent - ReparentNotify = xlib.ReparentNotify - # XConfigureEvent - ConfigureNotify = xlib.ConfigureNotify - # XGravityEvent - GravityNotify = xlib.GravityNotify - # XResizeRequestEvent - ResizeRequest = xlib.ResizeRequest - # XConfigureRequestEvent - ConfigureRequest = xlib.ConfigureRequest - # XCirculateEvent - CirculateNotify = xlib.CirculateNotify - # XCirculateRequestEvent - CirculateRequest = xlib.CirculateRequest - # XPropertyEvent - PropertyNotify = xlib.PropertyNotify - # XSelectionClearEvent - SelectionClear = xlib.SelectionClear - # XSelectionRequestEvent - SelectionRequest = xlib.SelectionRequest - # XSelectionEvent - SelectionNotify = xlib.SelectionNotify - # XColormapEvent - ColormapNotify = xlib.ColormapNotify - # XClientMessageEvent - ClientMessage = xlib.ClientMessage - # XMappingEvent - MappingNotify = xlib.MappingNotify - # XKeymapEvent - KeymapNotify = xlib.KeymapNotify - -class INPUT_EVENT_MASKS(pyenum.IntEnum): - NoEventMask = xlib.NoEventMask - StructureNotifyMask = xlib.StructureNotifyMask - SubstructureNotifyMask = xlib.SubstructureNotifyMask - SubstructureRedirectMask = xlib.SubstructureRedirectMask - PropertyChangeMask = xlib.PropertyChangeMask - FocusChangeMask = xlib.FocusChangeMask - KeyPressMask = xlib.KeyPressMask - KeyReleaseMask = xlib.KeyReleaseMask - ButtonPressMask = xlib.ButtonPressMask - ButtonReleaseMask = xlib.ButtonReleaseMask - -class KEY_MASKS(pyenum.IntEnum): - AnyModifier = xlib.AnyModifier - Mod1Mask = xlib.Mod1Mask - ControlMask = xlib.ControlMask - ShiftMask = xlib.ShiftMask - Mod2Mask = xlib.Mod2Mask - Mod4Mask = xlib.Mod4Mask - LockMask = xlib.LockMask - -class BUTTON_MASKS(pyenum.IntEnum): - AnyModifier = xlib.AnyModifier - Button1Mask = xlib.Button1Mask - Button2Mask = xlib.Button2Mask - Button3Mask = xlib.Button3Mask - Button4Mask = xlib.Button4Mask - Button5Mask = xlib.Button5Mask - -class BUTTONS(pyenum.IntEnum): - AnyButton = xlib.AnyButton - Button1 = xlib.Button1 - Button2 = xlib.Button2 - Button3 = xlib.Button3 - Button4 = xlib.Button4 - Button5 = xlib.Button5 - -class GRAB_MODE(pyenum.IntEnum): - GrabModeSync = xlib.GrabModeSync - GrabModeAsync = xlib.GrabModeAsync - -class WINDOW_VALUE_MASK(pyenum.IntEnum): - CWX = xlib.CWX - CWY = xlib.CWY - CWWidth = xlib.CWWidth - CWHeight = xlib.CWHeight - CWBorderWidth = xlib.CWBorderWidth - CWSibling = xlib.CWSibling - CWStackMode = xlib.CWStackMode - -class WINDOW_STACKING_METHOD(pyenum.IntEnum): - Above = xlib.Above - Below = xlib.Below - TopIf = xlib.TopIf - BottomIf = xlib.BottomIf - Opposite = xlib.Opposite - -class SET_PROPERTY_MODE(pyenum.IntEnum): - PropModeReplace = xlib.PropModeReplace - PropModePrepend = xlib.PropModePrepend - PropModeAppend = xlib.PropModeAppend - -class WINDOW_MAP_STATE(pyenum.IntEnum): - IsUnmapped = xlib.IsUnmapped - IsUnviewable = xlib.IsUnviewable - IsViewable = xlib.IsViewable - -class SCREENSAVER_STATE(pyenum.IntEnum): - ScreenSaverOff = xlib.ScreenSaverOff - ScreenSaverOn = xlib.ScreenSaverOn - ScreenSaverCycle = xlib.ScreenSaverCycle - ScreenSaverDisabled = xlib.ScreenSaverDisabled - -class SCREENSAVER_KIND(pyenum.IntEnum): - ScreenSaverBlanked = xlib.ScreenSaverBlanked - ScreenSaverInternal = xlib.ScreenSaverInternal - ScreenSaverExternal = xlib.ScreenSaverExternal - -class KB_GROUP_INDEX(pyenum.IntEnum): - XkbGroup1Index = xlib.XkbGroup1Index - XkbGroup2Index = xlib.XkbGroup2Index - XkbGroup3Index = xlib.XkbGroup3Index - XkbGroup4Index = xlib.XkbGroup4Index - XkbAnyGroup = xlib.XkbAnyGroup - XkbAllGroups = xlib.XkbAllGroups - -class NOTIFY_MODES(pyenum.IntEnum): - NotifyNormal = xlib.NotifyNormal - NotifyGrab = xlib.NotifyGrab - NotifyUngrab = xlib.NotifyUngrab - NotifyWhileGrabbed = xlib.NotifyWhileGrabbed - -class NOTIFY_DETAILS(pyenum.IntEnum): - NotifyAncestor = xlib.NotifyAncestor - NotifyVirtual = xlib.NotifyVirtual - NotifyInferior = xlib.NotifyInferior - NotifyNonlinear = xlib.NotifyNonlinear - NotifyNonlinearVirtual = xlib.NotifyNonlinearVirtual - NotifyPointer = xlib.NotifyPointer - NotifyPointerRoot = xlib.NotifyPointerRoot - NotifyDetailNone = xlib.NotifyDetailNone - -class PROPERTY_NOTIFICATION(pyenum.IntEnum): - PropertyNewValue = xlib.PropertyNewValue - PropertyDelete = xlib.PropertyDelete - -class PROPERTY_FORMAT(pyenum.Enum): - """ - Enum representing the valid formats when getting/setting a property. - - - CHAR: Format with value 8. The value of the property is a char array - - SHORT: Format with value 16. The value of the property is a short array - - LONG: Format with value 32. The value of the property is a long array - """ - - CHAR = (8, "b") - SHORT = (16, "h") - LONG = (32, "l") - - @classmethod - def new_from_value(cls, value: Union[str, int]) -> "PROPERTY_FORMAT": - for member in cls: - if value in member.value: - return member - raise ValueError(f"The value {value} is not in the enum members") - -class DPMS_POWER_LEVEL(pyenum.IntEnum): - DPMSModeOn = xlib.DPMSModeOn - DPMSModeStandby = xlib.DPMSModeStandby - DPMSModeSuspend = xlib.DPMSModeSuspend - DPMSModeOff = xlib.DPMSModeOff - -class PYLOOP_NEW_LOOP_FLAGS(pyenum.IntEnum): - EVFLAG_AUTO = libev.EVFLAG_AUTO - EVFLAG_NOENV = libev.EVFLAG_NOENV - EVFLAG_FORKCHECK = libev.EVFLAG_FORKCHECK - EVFLAG_NOINOTIFY = libev.EVFLAG_NOINOTIFY - EVFLAG_SIGNALFD = libev.EVFLAG_SIGNALFD - EVFLAG_NOSIGMASK = libev.EVFLAG_NOSIGMASK - EVBACKEND_SELECT = libev.EVBACKEND_SELECT - EVBACKEND_POLL = libev.EVBACKEND_POLL - EVBACKEND_EPOLL = libev.EVBACKEND_EPOLL - EVBACKEND_KQUEUE = libev.EVBACKEND_KQUEUE - EVBACKEND_DEVPOLL = libev.EVBACKEND_DEVPOLL - EVBACKEND_PORT = libev.EVBACKEND_PORT - EVBACKEND_ALL = libev.EVBACKEND_ALL - EVBACKEND_MASK = libev.EVBACKEND_MASK - -class PYLOOP_RUN_LOOP_FLAGS(pyenum.IntEnum): - EVRUN_ALWAYS = 0 # Keep handling events until either no event watchers are active anymore or "ev_break" was called - EVRUN_ONCE = libev.EVRUN_ONCE - EVRUN_NOWAIT = libev.EVRUN_NOWAIT - -class PYLOOP_BREAK_LOOP_FLAGS(pyenum.IntEnum): - EVBREAK_ALL = libev.EVBREAK_ALL - EVBREAK_ONE = libev.EVBREAK_ONE - EVBREAK_CANCEL = libev.EVBREAK_CANCEL - -class PYIOWATCHER_INIT_FLAGS(pyenum.IntEnum): - EV_READ = libev.EV_READ - EV_WRITE = libev.EV_WRITE - EV_READ_WRITE = libev.EV_READ | libev.EV_WRITE - - # Functions def PyXOpenDisplay(display_name: Optional[str]) -> Optional[PyDisplay]: diff --git a/pyproject.toml b/pyproject.toml index 388a0c0..60d6eb8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "orcsome3" -license = {file = "LICENSE"} +# SPDX form needs setuptools>=77, which dropped Python 3.8 — but wheels-cp38 (CI) resolves an older +# setuptools that rejects this form outright. python-publish.yml's wheels-cp38 job patches this file +# back to the old `{file=...}` form + classifier in its own checkout before building; every other +# consumer (this repo, validate, build_sdist, wheels-cp39-plus) uses the modern form below. +license = "MIT" +license-files = ["LICENSE"] authors = [ {name = "Ahsan Pérez", email = "ahsand.perez@gmail.com"} ] @@ -12,7 +17,6 @@ description = "Scripting extension for NETWM compliant window managers" requires-python = ">=3.8" classifiers = [ "Programming Language :: Python :: 3", - "License :: OSI Approved :: MIT License", "Development Status :: 4 - Beta", "Environment :: X11 Applications", "Topic :: Desktop Environment :: Window Managers", @@ -36,9 +40,19 @@ repository = "https://github.com/ahsand97/orcsome3" zip-safe = false packages = [ "orcsome3", + "orcsome3.icons", + "orcsome3.icons.hicolor", + "orcsome3.icons.hicolor.scalable", + "orcsome3.icons.hicolor.scalable.apps", "orcsome3.libs", "orcsome3.libs.build", "orcsome3.libs.cython_libs", + "orcsome3.libs.cython_libs.cairo", + "orcsome3.libs.cython_libs.imagemagick", + "orcsome3.libs.cython_libs.libev", + "orcsome3.libs.cython_libs.libgd", + "orcsome3.libs.cython_libs.resvg", + "orcsome3.libs.cython_libs.xlib", ] [tool.setuptools.cmdclass]