Skip to content

Commit

Permalink
ALL: Included PyWinBox module which hopefully better handles multi-mo…
Browse files Browse the repository at this point in the history
…nitor setups (macOS tests pending)

LINUX: Fixed geometry calculations (thanks to roym899 - https://github.com/roym899), removed ewmh and pynput dependencies
WINDOWS: Fixed getAllWindows() not returning all relevant windows (thanks to Xenolphthalein - https://github.com/Xenolphthalein)
MACOS: Fixed 'missing value' in window titles and app names (thanks to yjmd2222 - https://github.com/yjmd2222), fixed getClientFrame() to be invoked from non-main threads (thanks to super-iby)
  • Loading branch information
Kalmat committed Aug 21, 2023
1 parent 781fd56 commit 5c28207
Show file tree
Hide file tree
Showing 7 changed files with 467 additions and 556 deletions.
Binary file modified dist/PyWinCtl-0.0.44-py3-none-any.whl
Binary file not shown.
138 changes: 138 additions & 0 deletions src/ewmhlib/Props.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from enum import IntEnum
import Xlib.X


class Root:
SUPPORTED = "_NET_SUPPORTED"
CLIENT_LIST = "_NET_CLIENT_LIST"
CLIENT_LIST_STACKING = "_NET_CLIENT_LIST_STACKING"
NUMBER_OF_DESKTOPS = "_NET_NUMBER_OF_DESKTOPS"
DESKTOP_GEOMETRY = "_NET_DESKTOP_GEOMETRY"
DESKTOP_VIEWPORT = "_NET_DESKTOP_VIEWPORT"
CURRENT_DESKTOP = "_NET_CURRENT_DESKTOP"
DESKTOP_NAMES = "_NET_DESKTOP_NAMES"
ACTIVE = "_NET_ACTIVE_WINDOW"
WORKAREA = "_NET_WORKAREA"
SUPPORTING_WM_CHECK = "_NET_SUPPORTING_WM_CHECK"
VIRTUAL_ROOTS = "_NET_VIRTUAL_ROOTS"
SHOWING_DESKTOP = "_NET_SHOWING_DESKTOP"
DESKTOP_LAYOUT = "_NET_DESKTOP_LAYOUT"
# Additional Root properties (always related to a specific window)
CLOSE = "_NET_CLOSE_WINDOW"
MOVERESIZE = "_NET_MOVERESIZE_WINDOW"
WM_MOVERESIZE = "_NET_WM_MOVERESIZE"
RESTACK = "_NET_RESTACK_WINDOW"
REQ_FRAME_EXTENTS = "_NET_REQUEST_FRAME_EXTENTS"
# WM_PROTOCOLS messages
PROTOCOLS = "WM_PROTOCOLS"
PING = "_NET_WM_PING"
SYNC = "_NET_WM_SYNC_REQUEST"


class DesktopLayout(IntEnum):
ORIENTATION_HORZ = 0
ORIENTATION_VERT = 1
TOPLEFT = 0
TOPRIGHT = 1
BOTTOMRIGHT = 2
BOTTOMLEFT = 3


class Window:
NAME = "_NET_WM_NAME"
VISIBLE_NAME = "_NET_WM_VISIBLE_NAME"
ICON_NAME = "_NET_WM_ICON_NAME"
VISIBLE_ICON_NAME = "_NET_WM_VISIBLE_ICON_NAME"
DESKTOP = "_NET_WM_DESKTOP"
WM_WINDOW_TYPE = "_NET_WM_WINDOW_TYPE"
CHANGE_STATE = "WM_CHANGE_STATE"
WM_STATE = "_NET_WM_STATE"
ALLOWED_ACTIONS = "_NET_WM_ALLOWED_ACTIONS"
STRUT = "_NET_WM_STRUT"
STRUT_PARTIAL = "_NET_WM_STRUT_PARTIAL"
ICON_GEOMETRY = "_NET_WM_ICON_GEOMETRY"
ICON = "_NET_WM_ICON"
PID = "_NET_WM_PID"
HANDLED_ICONS = "_NET_WM_HANDLED_ICONS"
USER_TIME = "_NET_WM_USER_TIME"
FRAME_EXTENTS = "_NET_FRAME_EXTENTS"
# These are Root properties, but always related to a specific window
ACTIVE = "_NET_ACTIVE_WINDOW"
CLOSE = "_NET_CLOSE_WINDOW"
MOVERESIZE = "_NET_MOVERESIZE_WINDOW"
WM_MOVERESIZE = "_NET_WM_MOVERESIZE"
RESTACK = "_NET_RESTACK_WINDOW"
REQ_FRAME_EXTENTS = "_NET_REQUEST_FRAME_EXTENTS"
OPAQUE_REGION = "_NET_WM_OPAQUE_REGION"
BYPASS_COMPOSITOR = "_NET_WM_BYPASS_COMPOSITOR"


class WindowType:
DESKTOP = "_NET_WM_WINDOW_TYPE_DESKTOP"
DOCK = "_NET_WM_WINDOW_TYPE_DOCK"
TOOLBAR = "_NET_WM_WINDOW_TYPE_TOOLBAR"
MENU = "_NET_WM_WINDOW_TYPE_MENU"
UTILITY = "_NET_WM_WINDOW_TYPE_UTILITY"
SPLASH = "_NET_WM_WINDOW_TYPE_SPLASH"
DIALOG = "_NET_WM_WINDOW_TYPE_DIALOG"
NORMAL = "_NET_WM_WINDOW_TYPE_NORMAL"


class State:
NULL = "0"
MODAL = "_NET_WM_STATE_MODAL"
STICKY = "_NET_WM_STATE_STICKY"
MAXIMIZED_VERT = "_NET_WM_STATE_MAXIMIZED_VERT"
MAXIMIZED_HORZ = "_NET_WM_STATE_MAXIMIZED_HORZ"
SHADED = "_NET_WM_STATE_SHADED"
SKIP_TASKBAR = "_NET_WM_STATE_SKIP_TASKBAR"
SKIP_PAGER = "_NET_WM_STATE_SKIP_PAGER"
HIDDEN = "_NET_WM_STATE_HIDDEN"
FULLSCREEN = "_NET_WM_STATE_FULLSCREEN"
ABOVE = "_NET_WM_STATE_ABOVE"
BELOW = "_NET_WM_STATE_BELOW"
DEMANDS_ATTENTION = "_NET_WM_STATE_DEMANDS_ATTENTION"
FOCUSED = "_NET_WM_STATE_FOCUSED"


class StateAction(IntEnum):
REMOVE = 0
ADD = 1
TOGGLE = 2


class MoveResize(IntEnum):
SIZE_TOPLEFT = 0
SIZE_TOP = 1
SIZE_TOPRIGHT = 2
SIZE_RIGHT = 3
SIZE_BOTTOMRIGHT = 4
SIZE_BOTTOM = 5
SIZE_BOTTOMLEFT = 6
SIZE_LEFT = 7
MOVE = 8 # movement only
SIZE_KEYBOARD = 9 # size via keyboard
MOVE_KEYBOARD = 10 # move via keyboard


class DataFormat(IntEnum):
STR = 8
INT = 32


class Mode(IntEnum):
REPLACE = Xlib.X.PropModeReplace
APPEND = Xlib.X.PropModeAppend
PREPEND = Xlib.X.PropModePrepend


class StackMode(IntEnum):
ABOVE = Xlib.X.Above
BELOW = Xlib.X.Below


class HintAction(IntEnum):
KEEP = -1
REMOVE = -2


71 changes: 71 additions & 0 deletions src/ewmhlib/Structs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
from typing import List

from typing_extensions import TypedDict

from ctypes import Structure, c_int32, c_ulong, c_uint32
import Xlib.xobject
from Xlib.protocol.rq import Struct
from Xlib.xobject.drawable import Window as XWindow


class ScreensInfo(TypedDict):
screen_number: str
is_default: bool
screen: Struct
root: XWindow


class DisplaysInfo(TypedDict):
name: str
is_default: bool
screens: List[ScreensInfo]


"""
Perhaps unnecesary since structs below are defined in Xlib.xobject.icccm.*, though in a more complex way.
"""
class WmHints(TypedDict):
# {'flags': 103, 'input': 1, 'initial_state': 1, 'icon_pixmap': <Pixmap 0x02a22304>, 'icon_window': <Window 0x00000000>, 'icon_x': 0, 'icon_y': 0, 'icon_mask': <Pixmap 0x02a2230b>, 'window_group': <Window 0x02a00001>}
flags: int
input_mode: int
initial_state: int
icon_pixmap: Xlib.xobject.drawable.Pixmap
icon_window: Xlib.xobject.drawable.Window
icon_x: int
icon_y: int
icon_mask: Xlib.xobject.drawable.Pixmap
window_group: Xlib.xobject.drawable.Window


class Aspect(TypedDict):
num: int
denum: int


class WmNormalHints(TypedDict):
# {'flags': 848, 'min_width': 387, 'min_height': 145, 'max_width': 0, 'max_height': 0, 'width_inc': 9, 'height_inc': 18, 'min_aspect': <class 'Xlib.protocol.rq.DictWrapper'>({'num': 0, 'denum': 0}), 'max_aspect': <class 'Xlib.protocol.rq.DictWrapper'>({'num': 0, 'denum': 0}), 'base_width': 66, 'base_height': 101, 'win_gravity': 1}
flags: int
min_width: int
min_height: int
max_width: int
max_height: int
width_inc: int
height_inc: int
min_aspect: Aspect
max_aspect: Aspect
base_width: int
base_height: int
win_gravity: int


class _XWindowAttributes(Structure):
_fields_ = [('x', c_int32), ('y', c_int32),
('width', c_int32), ('height', c_int32), ('border_width', c_int32),
('depth', c_int32), ('visual', c_ulong), ('root', c_ulong),
('class', c_int32), ('bit_gravity', c_int32),
('win_gravity', c_int32), ('backing_store', c_int32),
('backing_planes', c_ulong), ('backing_pixel', c_ulong),
('save_under', c_int32), ('colourmap', c_ulong),
('mapinstalled', c_uint32), ('map_state', c_uint32),
('all_event_masks', c_ulong), ('your_event_mask', c_ulong),
('do_not_propagate_mask', c_ulong), ('override_redirect', c_int32), ('screen', c_ulong)]
25 changes: 25 additions & 0 deletions src/ewmhlib/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from __future__ import annotations

import sys
assert sys.platform == "linux"

from ._ewmhlib import (getAllDisplaysInfo, getDisplayFromRoot, getDisplayFromWindow,
getProperty, getPropertyValue, changeProperty, sendMessage, _xlibGetAllWindows,
defaultDisplay, defaultScreen, defaultRoot, RootWindow, defaultRootWindow, EwmhWindow
)
import ewmhlib.Props as Props
import ewmhlib.Structs as Structs

__all__ = [
"version", "getAllDisplaysInfo", "getDisplayFromRoot", "getDisplayFromWindow",
"getProperty", "getPropertyValue", "changeProperty", "sendMessage",
"defaultDisplay", "defaultScreen", "defaultRoot", "defaultRootWindow", "RootWindow", "EwmhWindow"
]


__version__ = "0.0.1"


def version(numberOnly: bool = True):
"""Returns the current version of ewmhlib module, in the form ''x.x.xx'' as string"""
return ("" if numberOnly else "EWMHlib-")+__version__
Loading

0 comments on commit 5c28207

Please sign in to comment.