From 8f09ab3eb9cfea1203e42eeda352766b746a6ac4 Mon Sep 17 00:00:00 2001 From: Kalmat Date: Mon, 23 Sep 2024 14:08:20 +0200 Subject: [PATCH] ALL: Added getAllWindowsDict() general function. Added getPID() method. LINUX: Added bad window filter to check for window.id == 0 --- src/pywinctl/_main.py | 15 ++++++++++++++- src/pywinctl/_pywinctl_linux.py | 19 +++++++++---------- src/pywinctl/_pywinctl_macos.py | 19 ++++++++----------- src/pywinctl/_pywinctl_win.py | 23 ++++++++++++----------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/pywinctl/_main.py b/src/pywinctl/_main.py index 1b03cd3..4bc0f6f 100644 --- a/src/pywinctl/_main.py +++ b/src/pywinctl/_main.py @@ -9,7 +9,7 @@ import time from abc import ABC, abstractmethod from collections.abc import Callable -from typing import Any, cast, List, Tuple, Union +from typing import Any, cast, List, Tuple, Union, TypedDict from pymonctl import findMonitorsAtPoint, getAllMonitors, getAllMonitorsDict, getMousePos as getMouse from pywinbox import PyWinBox, Box, Rect, Point, Size @@ -992,6 +992,19 @@ def displayWindowsUnderMouse(xOffset: int = 0, yOffset: int = 0) -> None: sys.stdout.flush() +class _WINDATA(TypedDict): + id: Union[int, tuple[str, str]] + display: list[str] + position: tuple[int, int] + size: tuple[int, int] + status: int + + +class _WINDICT(TypedDict): + pid: int + windows: dict[str, _WINDATA] + + if sys.platform == "darwin": from ._pywinctl_macos import (MacOSWindow as Window, checkPermissions, getActiveWindow, getActiveWindowTitle, getAllAppsNames, getAllAppsWindowsTitles, diff --git a/src/pywinctl/_pywinctl_linux.py b/src/pywinctl/_pywinctl_linux.py index 26b2f0a..b34fbef 100644 --- a/src/pywinctl/_pywinctl_linux.py +++ b/src/pywinctl/_pywinctl_linux.py @@ -22,7 +22,7 @@ import Xlib.ext from Xlib.xobject.drawable import Window as XWindow -from ._main import BaseWindow, Re, _WatchDog, _findMonitorName +from ._main import BaseWindow, Re, _WatchDog, _findMonitorName, _WINDATA, _WINDICT from ewmhlib import EwmhWindow, EwmhRoot, defaultEwmhRoot, Props from ewmhlib._ewmhlib import _xlibGetAllWindows @@ -264,7 +264,7 @@ def getAllAppsWindowsTitles(): return result -def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]]: +def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, _WINDICT]: """ Get all visible apps and windows info @@ -284,7 +284,7 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in :param tryToFilter: Windows ONLY. Set to ''True'' to try to get User (non-system) apps only (may skip real user apps) :return: python dictionary """ - result: dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]] = {} + result: dict[str, _WINDICT] = {} for win in getAllWindows(): winId = win.getHandle() appName = win.getAppName() @@ -294,18 +294,17 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in status = 1 elif win.isMaximized: status = 2 - winDict = { + pos = win.position + size = win.size + winDict: _WINDATA = { "id": winId, "display": win.getDisplay(), - "position": win.position, - "size": win.size, + "position": (pos.x, pos.y), + "size": (size.width, size.height), "status": status } if appName not in result.keys(): - result[appName] = {} - result[appName]["pìd"] = appPID - if "windows" not in result[appName].keys(): - result[appName]["windows"] = {} + result[appName] = {"pid": appPID, "windows": {}} result[appName]["windows"][win.title] = winDict return result diff --git a/src/pywinctl/_pywinctl_macos.py b/src/pywinctl/_pywinctl_macos.py index 27bc5ad..83548e4 100644 --- a/src/pywinctl/_pywinctl_macos.py +++ b/src/pywinctl/_pywinctl_macos.py @@ -21,7 +21,7 @@ import AppKit import Quartz -from ._main import BaseWindow, Re, _WatchDog, _findMonitorName +from ._main import BaseWindow, Re, _WatchDog, _findMonitorName, _WINDATA, _WINDICT from pywinbox import Size, Point, Rect, pointInBox @@ -311,7 +311,7 @@ def getAllAppsWindowsTitles(): return result -def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]]: +def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, _WINDICT]: """ Get all visible apps and windows info @@ -343,7 +343,7 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in .replace('missing value', '"missing value"') \ .replace("{", "[").replace("}", "]") res = ast.literal_eval(ret) - result: dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]] = {} + result: dict[str, _WINDICT] = {} if len(res) > 0: pids = res[0] apps = res[1] @@ -362,19 +362,16 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in status = 1 elif win.isMaximized: status = 2 - display = win.getDisplay() - if appName not in result.keys(): - result[appName] = {} - result[appName]["pid"] = pID - if "windows" not in result[appName].keys(): - result[appName]["windows"] = {} - result[appName]["windows"][title] = { + winDict: _WINDATA = { "id": winId, - "display": display, + "display": win.getDisplay(), "position": pos[j], "size": sizes[j], "status": status } + if appName not in result.keys(): + result[appName] = {"pid": pID, "windows": {}} + result[appName]["windows"][title] = winDict break return result diff --git a/src/pywinctl/_pywinctl_win.py b/src/pywinctl/_pywinctl_win.py index 6b98813..0c4280d 100644 --- a/src/pywinctl/_pywinctl_win.py +++ b/src/pywinctl/_pywinctl_win.py @@ -24,7 +24,7 @@ import win32api import win32gui -from ._main import BaseWindow, Re, _WatchDog, _findMonitorName +from ._main import BaseWindow, Re, _WatchDog, _findMonitorName, _WINDATA, _WINDICT from pywinbox import Size, Point, Rect, pointInBox # WARNING: Changes are not immediately applied, specially for hide/show (unmap/map) @@ -231,7 +231,7 @@ def getAllAppsWindowsTitles() -> dict[str, List[str]]: return result -def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]]: +def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, _WINDICT]: """ Get all visible apps and windows info @@ -241,7 +241,9 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in Values: "pid": app PID "windows": subdictionary of all app windows - "title": subdictionary of window info + Key: window title + + Values: "id": window handle "display": display in which window is mostly visible "position": window position (x, y) within display @@ -252,7 +254,7 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in :return: python dictionary """ process_list = _getAllApps(tryToFilter) - result: dict[str, int | dict[str, int | dict[str, str | dict[str, int | Point | Size | str]]]] = {} + result: dict[str, _WINDICT] = {} for win in getAllWindows(): winId = win.getHandle() pID = win32process.GetWindowThreadProcessId(winId) @@ -265,18 +267,17 @@ def getAllWindowsDict(tryToFilter: bool = False) -> dict[str, int | dict[str, in status = 1 elif win.isMaximized: status = 2 - winDict = { + pos = win.position + size = win.size + winDict: _WINDATA = { "id": winId, "display": win.getDisplay(), - "position": win.position, - "size": win.size, + "position": (pos.x, pos.y), + "size": (size.width, size.height), "status": status } if appName not in result.keys(): - result[appName] = {} - result[appName]["pìd"] = appPID - if "windows" not in result[appName].keys(): - result[appName]["windows"] = {} + result[appName] = {"pid": appPID, "windows": {}} result[appName]["windows"][win.title] = winDict break return result