abstract-windows 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- abstract_windows-0.0.1/PKG-INFO +71 -0
- abstract_windows-0.0.1/README.md +40 -0
- abstract_windows-0.0.1/pyproject.toml +3 -0
- abstract_windows-0.0.1/setup.cfg +4 -0
- abstract_windows-0.0.1/setup.py +34 -0
- abstract_windows-0.0.1/src/abstract_windows/__init__.py +3 -0
- abstract_windows-0.0.1/src/abstract_windows/browser_utils/__init__.py +1 -0
- abstract_windows-0.0.1/src/abstract_windows/browser_utils/browser_utils.py +66 -0
- abstract_windows-0.0.1/src/abstract_windows/string_comp/__init__.py +1 -0
- abstract_windows-0.0.1/src/abstract_windows/string_comp/string_compare.py +103 -0
- abstract_windows-0.0.1/src/abstract_windows/window_utils/__init__.py +1 -0
- abstract_windows-0.0.1/src/abstract_windows/window_utils/window_utils.py +183 -0
- abstract_windows-0.0.1/src/abstract_windows.egg-info/PKG-INFO +71 -0
- abstract_windows-0.0.1/src/abstract_windows.egg-info/SOURCES.txt +15 -0
- abstract_windows-0.0.1/src/abstract_windows.egg-info/dependency_links.txt +1 -0
- abstract_windows-0.0.1/src/abstract_windows.egg-info/requires.txt +2 -0
- abstract_windows-0.0.1/src/abstract_windows.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abstract_windows
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Home-page: https://github.com/AbstractEndeavors/abstract_windows
|
|
5
|
+
Author: putkoff
|
|
6
|
+
Author-email: partners@abstractendeavors.com
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.6
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: abstract_utilities
|
|
22
|
+
Requires-Dist: abstract_webserver
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# Unknown Package (vUnknown Version)
|
|
33
|
+
|
|
34
|
+
No description available
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install Unknown Package
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Dependencies
|
|
43
|
+
|
|
44
|
+
None
|
|
45
|
+
|
|
46
|
+
## Modules
|
|
47
|
+
|
|
48
|
+
### src/abstract_react/replace_utils.py
|
|
49
|
+
|
|
50
|
+
Description of script based on prompt: You are analyzing a Python script 'replace_utils.p (mock response)
|
|
51
|
+
|
|
52
|
+
### src/abstract_react/__init__.py
|
|
53
|
+
|
|
54
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
55
|
+
|
|
56
|
+
### src/abstract_react/import_utils.py
|
|
57
|
+
|
|
58
|
+
Description of script based on prompt: You are analyzing a Python script 'import_utils.py (mock response)
|
|
59
|
+
|
|
60
|
+
### src/__init__.py
|
|
61
|
+
|
|
62
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
63
|
+
|
|
64
|
+
### src/abstract_react/utils.py
|
|
65
|
+
|
|
66
|
+
Description of script based on prompt: You are analyzing a Python script 'utils.py' locat (mock response)
|
|
67
|
+
|
|
68
|
+
### src/abstract_react/abstract_react.py
|
|
69
|
+
|
|
70
|
+
Description of script based on prompt: You are analyzing a Python script 'abstract_react. (mock response)
|
|
71
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Unknown Package (vUnknown Version)
|
|
2
|
+
|
|
3
|
+
No description available
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install Unknown Package
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Dependencies
|
|
12
|
+
|
|
13
|
+
None
|
|
14
|
+
|
|
15
|
+
## Modules
|
|
16
|
+
|
|
17
|
+
### src/abstract_react/replace_utils.py
|
|
18
|
+
|
|
19
|
+
Description of script based on prompt: You are analyzing a Python script 'replace_utils.p (mock response)
|
|
20
|
+
|
|
21
|
+
### src/abstract_react/__init__.py
|
|
22
|
+
|
|
23
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
24
|
+
|
|
25
|
+
### src/abstract_react/import_utils.py
|
|
26
|
+
|
|
27
|
+
Description of script based on prompt: You are analyzing a Python script 'import_utils.py (mock response)
|
|
28
|
+
|
|
29
|
+
### src/__init__.py
|
|
30
|
+
|
|
31
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
32
|
+
|
|
33
|
+
### src/abstract_react/utils.py
|
|
34
|
+
|
|
35
|
+
Description of script based on prompt: You are analyzing a Python script 'utils.py' locat (mock response)
|
|
36
|
+
|
|
37
|
+
### src/abstract_react/abstract_react.py
|
|
38
|
+
|
|
39
|
+
Description of script based on prompt: You are analyzing a Python script 'abstract_react. (mock response)
|
|
40
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from time import time
|
|
2
|
+
import setuptools
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
setuptools.setup(
|
|
6
|
+
name='abstract_windows',
|
|
7
|
+
version='0.0.1',
|
|
8
|
+
author='putkoff',
|
|
9
|
+
author_email='partners@abstractendeavors.com',
|
|
10
|
+
description="",
|
|
11
|
+
long_description=long_description,
|
|
12
|
+
long_description_content_type='text/markdown',
|
|
13
|
+
url='https://github.com/AbstractEndeavors/abstract_windows',
|
|
14
|
+
classifiers=[
|
|
15
|
+
'Development Status :: 3 - Alpha',
|
|
16
|
+
'Intended Audience :: Developers',
|
|
17
|
+
'Topic :: Software Development :: Libraries',
|
|
18
|
+
'License :: OSI Approved :: MIT License',
|
|
19
|
+
'Programming Language :: Python :: 3',
|
|
20
|
+
'Programming Language :: Python :: 3.6',
|
|
21
|
+
'Programming Language :: Python :: 3.7',
|
|
22
|
+
'Programming Language :: Python :: 3.8',
|
|
23
|
+
'Programming Language :: Python :: 3.9',
|
|
24
|
+
'Programming Language :: Python :: 3.10',
|
|
25
|
+
'Programming Language :: Python :: 3.11',
|
|
26
|
+
'Programming Language :: Python :: 3.12',
|
|
27
|
+
],
|
|
28
|
+
install_requires=['abstract_utilities','abstract_webserver'],
|
|
29
|
+
package_dir={"": "src"},
|
|
30
|
+
packages=setuptools.find_packages(where="src"),
|
|
31
|
+
python_requires=">=3.6",
|
|
32
|
+
# Add this line to include wheel format in your distribution
|
|
33
|
+
setup_requires=['wheel'],
|
|
34
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .browser_utils import *
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import time
|
|
3
|
+
from typing import List
|
|
4
|
+
from ..string_comp import *
|
|
5
|
+
from ..window_utils import *
|
|
6
|
+
# tweak if your browser uses Page_Down instead of Tab
|
|
7
|
+
NEXT_TAB_KEY = "ctrl+Tab"
|
|
8
|
+
# how many times to press before giving up
|
|
9
|
+
MAX_TABS = 50
|
|
10
|
+
# time for browser to update title
|
|
11
|
+
DELAY = 0.1
|
|
12
|
+
# Browser title signatures
|
|
13
|
+
BROWSER_PATTERNS = [
|
|
14
|
+
'Mozilla', 'Firefox', 'Chrome', 'Chromium',
|
|
15
|
+
'Microsoft Edge', 'Opera', 'Safari'
|
|
16
|
+
]
|
|
17
|
+
def is_browser(win):
|
|
18
|
+
if get_strings_in_string(win.get('window_title'),BROWSER_PATTERNS):
|
|
19
|
+
return True
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
def get_tab_titles(win):
|
|
23
|
+
win_id = win["window_id"]
|
|
24
|
+
tab_titles = cycle_tabs(win_id)
|
|
25
|
+
win['tab_titles'] = tab_titles
|
|
26
|
+
return win
|
|
27
|
+
|
|
28
|
+
def get_browsers(parsed_windows=None,active_windows=None):
|
|
29
|
+
parsed_windows = parsed_windows or get_parsed_windows()
|
|
30
|
+
browsers = [get_tab_titles(parsed_window) for parsed_window in parsed_windows if is_browser(parsed_window)]
|
|
31
|
+
return browsers
|
|
32
|
+
|
|
33
|
+
def activate_window(win_id: str):
|
|
34
|
+
subprocess.run(["xdotool", "windowactivate", "--sync", win_id], check=True)
|
|
35
|
+
|
|
36
|
+
def get_window_title(win_id: str) -> str:
|
|
37
|
+
res = subprocess.run(
|
|
38
|
+
["xdotool", "getwindowname", win_id],
|
|
39
|
+
capture_output=True, text=True, check=True
|
|
40
|
+
)
|
|
41
|
+
return res.stdout.strip()
|
|
42
|
+
|
|
43
|
+
def switch_tab(win_id: str):
|
|
44
|
+
# sends the next‐tab key only to that window
|
|
45
|
+
subprocess.run(
|
|
46
|
+
["xdotool", "key", "--window", win_id, NEXT_TAB_KEY],
|
|
47
|
+
check=True
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def cycle_tabs(win_id: str,window_name=None) -> List[str]:
|
|
51
|
+
"""Returns the ordered list of tab-titles in the given window."""
|
|
52
|
+
activate_window(win_id)
|
|
53
|
+
first_title = get_window_title(win_id)
|
|
54
|
+
titles = [first_title]
|
|
55
|
+
|
|
56
|
+
for _ in range(MAX_TABS):
|
|
57
|
+
switch_tab(win_id)
|
|
58
|
+
time.sleep(DELAY)
|
|
59
|
+
title = get_window_title(win_id)
|
|
60
|
+
if window_name and title == window_name:
|
|
61
|
+
return
|
|
62
|
+
if title == first_title:
|
|
63
|
+
break
|
|
64
|
+
titles.append(title)
|
|
65
|
+
|
|
66
|
+
return titles
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .string_compare import *
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from abstract_utilities import make_list
|
|
2
|
+
def get_strings_in_string(string,strings):
|
|
3
|
+
for comp_string in strings:
|
|
4
|
+
if comp_string.lower() in string.lower():
|
|
5
|
+
return True
|
|
6
|
+
return False
|
|
7
|
+
def find_longest_common_substring(string, comp_string):
|
|
8
|
+
# Find the longest common substring
|
|
9
|
+
min_len = min(len(string), len(comp_string))
|
|
10
|
+
for length in range(min_len, 0, -1):
|
|
11
|
+
for i in range(len(string) - length + 1):
|
|
12
|
+
substring = string[i:i + length]
|
|
13
|
+
if substring in comp_string:
|
|
14
|
+
return substring
|
|
15
|
+
return None
|
|
16
|
+
|
|
17
|
+
def get_string_confidence(string,string_remains):
|
|
18
|
+
string_len = len(string)
|
|
19
|
+
remains_str = ''.join(string_remains)
|
|
20
|
+
remains_len = len(remains_str)
|
|
21
|
+
remains_perc = 0
|
|
22
|
+
confidence = 1
|
|
23
|
+
if remains_len:
|
|
24
|
+
remains_perc = remains_len/string_len
|
|
25
|
+
confidence = 1 - remains_perc
|
|
26
|
+
return confidence
|
|
27
|
+
def remove_substring(string, substring):
|
|
28
|
+
# Remove the first occurrence of substring and return remaining parts
|
|
29
|
+
idx = string.find(substring)
|
|
30
|
+
if idx == -1:
|
|
31
|
+
return [string]
|
|
32
|
+
remains = [string[:idx], string[idx + len(substring):]]
|
|
33
|
+
return [r for r in remains if r] # Remove empty strings
|
|
34
|
+
|
|
35
|
+
def compare_strings(string, comp_string):
|
|
36
|
+
results = []
|
|
37
|
+
|
|
38
|
+
# Initialize with the original strings
|
|
39
|
+
current_strings = [(string, comp_string)]
|
|
40
|
+
|
|
41
|
+
while current_strings:
|
|
42
|
+
new_strings = []
|
|
43
|
+
for s, cs in current_strings:
|
|
44
|
+
# Find the longest common substring
|
|
45
|
+
common = find_longest_common_substring(s, cs)
|
|
46
|
+
if not common:
|
|
47
|
+
continue # No common substring, move to next pair
|
|
48
|
+
|
|
49
|
+
# Record the found substring and remaining parts
|
|
50
|
+
string_remains = remove_substring(s, common)
|
|
51
|
+
comp_string_remains = remove_substring(cs, common)
|
|
52
|
+
|
|
53
|
+
# Store the result
|
|
54
|
+
results.append({
|
|
55
|
+
"found": common,
|
|
56
|
+
"string": {"remains": string_remains},
|
|
57
|
+
"comp_string": {"remains": comp_string_remains}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
# Add remaining parts for further processing
|
|
61
|
+
for sr in string_remains:
|
|
62
|
+
for csr in comp_string_remains:
|
|
63
|
+
new_strings.append((sr, csr))
|
|
64
|
+
|
|
65
|
+
current_strings = new_strings
|
|
66
|
+
string_remains = results[-1].get('string',{}).get('remains')
|
|
67
|
+
string_confidence = get_string_confidence(string,string_remains)
|
|
68
|
+
comp_string_remains = results[-1].get('comp_string',{}).get('remains')
|
|
69
|
+
comp_string_confidence = get_string_confidence(comp_string,comp_string_remains)
|
|
70
|
+
results = {"string":string,
|
|
71
|
+
"comp_string":comp_string,
|
|
72
|
+
"results":results,
|
|
73
|
+
"found":[result['found'] for result in results if result],
|
|
74
|
+
"confidence":{
|
|
75
|
+
"string":string_confidence,
|
|
76
|
+
"comp_string":comp_string_confidence
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return results
|
|
80
|
+
|
|
81
|
+
def return_best_comp_strings(string, comp_strings):
|
|
82
|
+
results = []
|
|
83
|
+
comp_strings = make_list(comp_strings)
|
|
84
|
+
for comp_string in comp_strings:
|
|
85
|
+
result = compare_strings(string, comp_string)
|
|
86
|
+
results.append(result)
|
|
87
|
+
|
|
88
|
+
confidence_results = None
|
|
89
|
+
for i, result in enumerate(results):
|
|
90
|
+
confidence = result.get('confidence', {})
|
|
91
|
+
string_confidence = confidence.get('string', 0)
|
|
92
|
+
comp_string_confidence = confidence.get('comp_string', 0)
|
|
93
|
+
if confidence_results is None:
|
|
94
|
+
#if string_confidence>.70:
|
|
95
|
+
confidence_results = [string_confidence, comp_string_confidence, i]
|
|
96
|
+
elif string_confidence > confidence_results[0]:
|
|
97
|
+
confidence_results = [string_confidence, comp_string_confidence, i]
|
|
98
|
+
elif string_confidence == confidence_results[0]:
|
|
99
|
+
if comp_string_confidence > confidence_results[1]:
|
|
100
|
+
confidence_results = [string_confidence, comp_string_confidence, i]
|
|
101
|
+
|
|
102
|
+
return comp_strings[confidence_results[2]]
|
|
103
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .window_utils import *
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
from typing import List, Dict, Optional, Union, Callable
|
|
2
|
+
import threading
|
|
3
|
+
import re
|
|
4
|
+
import subprocess
|
|
5
|
+
from Xlib import X, display
|
|
6
|
+
from Xlib.ext import randr
|
|
7
|
+
from difflib import get_close_matches
|
|
8
|
+
XRANDR_CMD = ["xrandr"] # or ["xrandr", "--listmonitors"] if you prefer
|
|
9
|
+
WMCTRL_LIST_CMD = ['wmctrl', '-l', '-p']
|
|
10
|
+
WMCTRL_MOVE_CMD = ['wmctrl', '-i', '-r']
|
|
11
|
+
XDOTOOL_GEOMETRY_CMD = ['xdotool', 'getwindowgeometry']
|
|
12
|
+
|
|
13
|
+
# Regex patterns
|
|
14
|
+
|
|
15
|
+
MONITOR_REGEX = re.compile(
|
|
16
|
+
r"""^
|
|
17
|
+
(?P<name>\S+)\s+ # e.g. "DisplayPort-1-2"
|
|
18
|
+
connected # literal word
|
|
19
|
+
(?:\s+primary)? # optional " primary"
|
|
20
|
+
\s+
|
|
21
|
+
(?P<width>\d+)x(?P<height>\d+) # resolution, e.g. "2560x1440"
|
|
22
|
+
\+(?P<x>\d+)\+(?P<y>\d+) # offsets, e.g. "+0+0"
|
|
23
|
+
""",
|
|
24
|
+
re.VERBOSE
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
POSITION_REGEX = re.compile(r'Position:\s+(\d+),(\d+)')
|
|
28
|
+
GEOMETRY_REGEX = re.compile(r'Geometry:\s+(\d+)x(\d+)')
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_monitors():
|
|
36
|
+
monitors = []
|
|
37
|
+
try:
|
|
38
|
+
result = subprocess.run(
|
|
39
|
+
XRANDR_CMD, capture_output=True, text=True, check=True
|
|
40
|
+
)
|
|
41
|
+
for line in result.stdout.splitlines():
|
|
42
|
+
m = MONITOR_REGEX.search(line)
|
|
43
|
+
if not m:
|
|
44
|
+
continue
|
|
45
|
+
gd = m.groupdict()
|
|
46
|
+
monitors.append({
|
|
47
|
+
"name": gd["name"],
|
|
48
|
+
"x": int(gd["x"]),
|
|
49
|
+
"y": int(gd["y"]),
|
|
50
|
+
"width": int(gd["width"]),
|
|
51
|
+
"height": int(gd["height"]),
|
|
52
|
+
})
|
|
53
|
+
except subprocess.SubprocessError as e:
|
|
54
|
+
print(f"Error running xrandr: {e}")
|
|
55
|
+
return monitors
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_strings_in_string(string,strings):
|
|
60
|
+
for comp_string in strings:
|
|
61
|
+
if comp_string.lower() in string.lower():
|
|
62
|
+
return True
|
|
63
|
+
return False
|
|
64
|
+
def get_windows_list():
|
|
65
|
+
result = subprocess.run(
|
|
66
|
+
WMCTRL_LIST_CMD, capture_output=True, text=True, check=True
|
|
67
|
+
)
|
|
68
|
+
windows = result.stdout.splitlines()
|
|
69
|
+
return windows
|
|
70
|
+
def get_filters(
|
|
71
|
+
windows: List[str],
|
|
72
|
+
find_window_id: Optional[str] = None,
|
|
73
|
+
find_desktop: Optional[str] = None,
|
|
74
|
+
find_pid: Optional[str] = None,
|
|
75
|
+
find_host: Optional[str] = None,
|
|
76
|
+
find_window_title: Optional[str] = None
|
|
77
|
+
):
|
|
78
|
+
filters = {k: v for k, v in {
|
|
79
|
+
'window_id': find_window_id,
|
|
80
|
+
'desktop': find_desktop,
|
|
81
|
+
'pid': find_pid,
|
|
82
|
+
'host': find_host,
|
|
83
|
+
'window_title': find_window_title
|
|
84
|
+
}.items() if v is not None}
|
|
85
|
+
return filters
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_monitor_for_window(
|
|
89
|
+
window_id: Optional[str] = None,
|
|
90
|
+
x: Optional[int] = None,
|
|
91
|
+
y: Optional[int] = None
|
|
92
|
+
) -> Dict[str, Union[str, int]]:
|
|
93
|
+
"""Determine which monitor a given window (or coordinate) is on."""
|
|
94
|
+
|
|
95
|
+
if window_id and x is None and y is None:
|
|
96
|
+
geom = get_window_geometry(window_id = window_id)
|
|
97
|
+
if geom is None:
|
|
98
|
+
return {}
|
|
99
|
+
x, y = geom['x'], geom['y']
|
|
100
|
+
|
|
101
|
+
if x is None or y is None:
|
|
102
|
+
return {}
|
|
103
|
+
for mon in get_monitors():
|
|
104
|
+
if mon['x'] <= x < mon['x'] + mon['width'] and \
|
|
105
|
+
mon['y'] <= y < mon['y'] + mon['height']:
|
|
106
|
+
return {
|
|
107
|
+
'monitor_name': mon['name'],
|
|
108
|
+
'monitor_details': f"{mon['width']}x{mon['height']}+{mon['x']}+{mon['y']}",
|
|
109
|
+
'win_x': x,
|
|
110
|
+
'win_y': y
|
|
111
|
+
}
|
|
112
|
+
return {}
|
|
113
|
+
def parse_window(window):
|
|
114
|
+
parts = window.split(None, 4)
|
|
115
|
+
if len(parts) >= 5:
|
|
116
|
+
win_id, desktop, pid, host, title = parts
|
|
117
|
+
monitor_info = get_monitor_for_window(window_id=win_id)
|
|
118
|
+
window_geometry = get_window_geometry(window_id=win_id)
|
|
119
|
+
info = {
|
|
120
|
+
'window_id': win_id, 'desktop': desktop, 'pid': pid,
|
|
121
|
+
'host': host, 'window_title': title,'monitor_info':monitor_info,
|
|
122
|
+
'window_geometry':window_geometry
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
info.update(monitor_info)
|
|
126
|
+
return info
|
|
127
|
+
def filter_window(info,filters={}):
|
|
128
|
+
if filters and all(parsed_window[k] == v for k, v in filters.items()):
|
|
129
|
+
return info
|
|
130
|
+
def parse_windows(windows,filters={}):
|
|
131
|
+
parsed_windows = []
|
|
132
|
+
for window in windows:
|
|
133
|
+
parsed_window = parse_window(window)
|
|
134
|
+
filtered_window = filter_window(parsed_window,filters=filters)
|
|
135
|
+
if filtered_window:
|
|
136
|
+
return filtered_window
|
|
137
|
+
if parsed_window:
|
|
138
|
+
parsed_windows.append(parsed_window)
|
|
139
|
+
return parsed_windows
|
|
140
|
+
def get_window_items(
|
|
141
|
+
windows: List[str],
|
|
142
|
+
find_window_id: Optional[str] = None,
|
|
143
|
+
find_desktop: Optional[str] = None,
|
|
144
|
+
find_pid: Optional[str] = None,
|
|
145
|
+
find_host: Optional[str] = None,
|
|
146
|
+
find_window_title: Optional[str] = None
|
|
147
|
+
) -> Union[Dict[str, str], List[Dict[str, str]]]:
|
|
148
|
+
"""Parse `wmctrl -l -p` output, optionally filtering."""
|
|
149
|
+
filters = get_filters(
|
|
150
|
+
windows=windows,
|
|
151
|
+
find_window_id= find_window_id,
|
|
152
|
+
find_desktop= find_desktop,
|
|
153
|
+
find_pid= find_pid,
|
|
154
|
+
find_host= find_host,
|
|
155
|
+
find_window_title= find_window_title
|
|
156
|
+
)
|
|
157
|
+
parsed = parse_windows(windows,filters)
|
|
158
|
+
return parsed
|
|
159
|
+
def get_window_geometry(window_id: str) -> Optional[Dict[str, int]]:
|
|
160
|
+
"""Get window position (x, y) and size (width, height) using xdotool."""
|
|
161
|
+
try:
|
|
162
|
+
result = subprocess.run(
|
|
163
|
+
XDOTOOL_GEOMETRY_CMD + [window_id],
|
|
164
|
+
capture_output=True, text=True, check=True
|
|
165
|
+
)
|
|
166
|
+
pos_m = POSITION_REGEX.search(result.stdout)
|
|
167
|
+
size_m = GEOMETRY_REGEX.search(result.stdout)
|
|
168
|
+
if pos_m and size_m:
|
|
169
|
+
return {
|
|
170
|
+
'x': int(pos_m.group(1)),
|
|
171
|
+
'y': int(pos_m.group(2)),
|
|
172
|
+
'width': int(size_m.group(1)),
|
|
173
|
+
'height': int(size_m.group(2))
|
|
174
|
+
}
|
|
175
|
+
return None
|
|
176
|
+
except subprocess.SubprocessError as e:
|
|
177
|
+
print(f"Error getting geometry: {e}")
|
|
178
|
+
return None
|
|
179
|
+
def get_parsed_windows():
|
|
180
|
+
windows = get_windows_list()
|
|
181
|
+
filters = get_filters(windows=windows)
|
|
182
|
+
parsed_windows = parse_windows(windows=windows,filters=filters)
|
|
183
|
+
return parsed_windows
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abstract_windows
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Home-page: https://github.com/AbstractEndeavors/abstract_windows
|
|
5
|
+
Author: putkoff
|
|
6
|
+
Author-email: partners@abstractendeavors.com
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.6
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: abstract_utilities
|
|
22
|
+
Requires-Dist: abstract_webserver
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: author-email
|
|
25
|
+
Dynamic: classifier
|
|
26
|
+
Dynamic: description
|
|
27
|
+
Dynamic: description-content-type
|
|
28
|
+
Dynamic: home-page
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# Unknown Package (vUnknown Version)
|
|
33
|
+
|
|
34
|
+
No description available
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install Unknown Package
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Dependencies
|
|
43
|
+
|
|
44
|
+
None
|
|
45
|
+
|
|
46
|
+
## Modules
|
|
47
|
+
|
|
48
|
+
### src/abstract_react/replace_utils.py
|
|
49
|
+
|
|
50
|
+
Description of script based on prompt: You are analyzing a Python script 'replace_utils.p (mock response)
|
|
51
|
+
|
|
52
|
+
### src/abstract_react/__init__.py
|
|
53
|
+
|
|
54
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
55
|
+
|
|
56
|
+
### src/abstract_react/import_utils.py
|
|
57
|
+
|
|
58
|
+
Description of script based on prompt: You are analyzing a Python script 'import_utils.py (mock response)
|
|
59
|
+
|
|
60
|
+
### src/__init__.py
|
|
61
|
+
|
|
62
|
+
Description of script based on prompt: You are analyzing a Python script '__init__.py' lo (mock response)
|
|
63
|
+
|
|
64
|
+
### src/abstract_react/utils.py
|
|
65
|
+
|
|
66
|
+
Description of script based on prompt: You are analyzing a Python script 'utils.py' locat (mock response)
|
|
67
|
+
|
|
68
|
+
### src/abstract_react/abstract_react.py
|
|
69
|
+
|
|
70
|
+
Description of script based on prompt: You are analyzing a Python script 'abstract_react. (mock response)
|
|
71
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
src/abstract_windows/__init__.py
|
|
5
|
+
src/abstract_windows.egg-info/PKG-INFO
|
|
6
|
+
src/abstract_windows.egg-info/SOURCES.txt
|
|
7
|
+
src/abstract_windows.egg-info/dependency_links.txt
|
|
8
|
+
src/abstract_windows.egg-info/requires.txt
|
|
9
|
+
src/abstract_windows.egg-info/top_level.txt
|
|
10
|
+
src/abstract_windows/browser_utils/__init__.py
|
|
11
|
+
src/abstract_windows/browser_utils/browser_utils.py
|
|
12
|
+
src/abstract_windows/string_comp/__init__.py
|
|
13
|
+
src/abstract_windows/string_comp/string_compare.py
|
|
14
|
+
src/abstract_windows/window_utils/__init__.py
|
|
15
|
+
src/abstract_windows/window_utils/window_utils.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abstract_windows
|