Skip to content

Commit

Permalink
ALL: Added PyMonCtl module to improve multi-monitor capabilities, add…
Browse files Browse the repository at this point in the history
…ed setParent() method. Reorganized to avoid IDEs showing external and / or private elements

WINDOWS: Simplified alwaysOnBottom(), found a smarter way to refresh window after bringing it back with sendBehind()
MACOSNSWINDOW: Added experimental acceptInput() method (not possible in AppleScript version)
  • Loading branch information
Kalmat committed Aug 28, 2023
1 parent d5a7908 commit f09a4a3
Show file tree
Hide file tree
Showing 2 changed files with 0 additions and 104 deletions.
Binary file modified dist/PyWinCtl-0.0.50-py3-none-any.whl
Binary file not shown.
104 changes: 0 additions & 104 deletions src/pywinctl/_pywinctl_win.py
Original file line number Diff line number Diff line change
Expand Up @@ -1252,110 +1252,6 @@ class _ScreenValue(TypedDict):
colordepth: int


def getAllScreens() -> dict[str, _ScreenValue]:
"""
load all monitors plugged to the pc, as a dict
:return: Monitors info as python dictionary
Output Format:
Key:
Display name
Values:
"id":
display index as returned by EnumDisplayDevices()
"is_primary":
''True'' if monitor is primary (shows clock and notification area, sign in, lock, CTRL+ALT+DELETE screens...)
"pos":
Point(x, y) struct containing the display position ((0, 0) for the primary screen)
"size":
Size(width, height) struct containing the display size, in pixels
"workarea":
Rect(left, top, right, bottom) struct with the screen workarea, in pixels
"scale":
Scale ratio, as a tuple of (x, y) scale percentage
"dpi":
Dots per inch, as a tuple of (x, y) dpi values
"orientation":
Display orientation: 0 - Landscape / 1 - Portrait / 2 - Landscape (reversed) / 3 - Portrait (reversed)
"frequency":
Refresh rate of the display, in Hz
"colordepth":
Bits per pixel referred to the display color depth
"""
# https://stackoverflow.com/questions/35814309/winapi-changedisplaysettingsex-does-not-work
result: dict[str, _ScreenValue] = {}
dpiAware = ctypes.windll.user32.GetAwarenessFromDpiAwarenessContext(ctypes.windll.user32.GetThreadDpiAwarenessContext())
if dpiAware == 0:
ctypes.windll.shcore.SetProcessDpiAwareness(2)
monitors = win32api.EnumDisplayMonitors()
i = 0
while True:
try:
dev = win32api.EnumDisplayDevices(None, i, 0)
except:
break

if dev and dev.StateFlags & win32con.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP:
try:
# Device content: http://timgolden.me.uk/pywin32-docs/PyDISPLAY_DEVICE.html
# Settings content: http://timgolden.me.uk/pywin32-docs/PyDEVMODE.html
monitor_info = None
monitor = None
for mon in monitors:
monitor = mon[0].handle
monitor_info = win32api.GetMonitorInfo(monitor)
if monitor_info["Device"] == dev.DeviceName:
break

if monitor_info:
name = dev.DeviceName
x, y, r, b = monitor_info["Monitor"]
wx, wy, wr, wb = monitor_info["Work"]
settings = win32api.EnumDisplaySettings(dev.DeviceName, win32con.ENUM_CURRENT_SETTINGS)
# values seem to be affected by the scale factor of the first display
wr, wb = wx + settings.PelsWidth + (wr - r), wy + settings.PelsHeight + (wb - b)
is_primary = ((x, y) == (0, 0))
r, b = x + settings.PelsWidth, y + settings.PelsHeight
pScale = ctypes.c_uint()
ctypes.windll.shcore.GetScaleFactorForMonitor(monitor, ctypes.byref(pScale))
scale = pScale.value
dpiX = ctypes.c_uint()
dpiY = ctypes.c_uint()
ctypes.windll.shcore.GetDpiForMonitor(monitor, 0, ctypes.byref(dpiX), ctypes.byref(dpiY))
rot = settings.DisplayOrientation
freq = settings.DisplayFrequency
depth = settings.BitsPerPel

result[name + "_" + str(i)] = {
"id": i,
# "is_primary": monitor_info.get("Flags", 0) & win32con.MONITORINFOF_PRIMARY == 1,
"is_primary": is_primary,
"pos": Point(x, y),
"size": Size(r - x, b - y),
"workarea": Rect(wx, wy, wr, wb),
"scale": (scale, scale),
"dpi": (dpiX.value, dpiY.value),
"orientation": rot,
"frequency": freq,
"colordepth": depth
}
except:
# print(traceback.format_exc())
pass
i += 1
return result


def forceStop(self):
thread_id = self.getTid()
if thread_id is not None:
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)


# Futile attempt to get the taskbar buttons handles without using pywinauto (but useful as "hard" pywin32 example!)
# def _getSysTrayButtons(window_class: str = ""):
# # https://stackoverflow.com/questions/31068541/how-to-use-win32gui-or-similar-to-click-an-other-window-toolstrip1-item-button
Expand Down

0 comments on commit f09a4a3

Please sign in to comment.