Skip to content

Commit

Permalink
fix: dpi unaware window showing across multiple monitors
Browse files Browse the repository at this point in the history
  • Loading branch information
klesh committed Apr 6, 2024
1 parent f5d457e commit 8b92624
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/jigsawwm/w32/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from ctypes import *
from ctypes.wintypes import *
from typing import List
from enum import IntEnum

kernel32 = WinDLL("kernel32", use_last_error=True)
advapi32 = WinDLL("advapi32", use_last_error=True)
psapi = WinDLL("psapi", use_last_error=True)
shcore = WinDLL("shcore", use_last_error=True)

TOKEN_QUERY = DWORD(8)

Expand Down Expand Up @@ -125,6 +127,18 @@ def get_session_id():
kernel32.ProcessIdToSessionId(kernel32.GetCurrentProcessId(), byref(session_id))
return kernel32.WTSGetActiveConsoleSessionId()

class ProcessDpiAwareness(IntEnum):
PROCESS_DPI_UNAWARE = 0,
PROCESS_SYSTEM_DPI_AWARE = 1,
PROCESS_PER_MONITOR_DPI_AWARE = 2

def get_process_dpi_awareness(pid: int) -> ProcessDpiAwareness:
"""Retrieves the DPI awareness of the process"""
hprc = open_process_for_limited_query(pid)
awareness = c_int()
if shcore.GetProcessDpiAwareness(hprc, pointer(awareness)):
raise WinError(get_last_error())
return ProcessDpiAwareness(awareness.value)

if __name__ == "__main__":
# import sys
Expand Down
6 changes: 6 additions & 0 deletions src/jigsawwm/w32/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,11 @@ def is_evelated(self):
"""Check if window is elevated (Administrator)"""
return process.is_elevated(self.pid)

@property
def dpi_awareness(self):
"""Check if window is api aware"""
return process.get_process_dpi_awareness(self.pid)

@property
def is_cloaked(self) -> bool:
"""Check if window is cloaked (DWM)
Expand Down Expand Up @@ -547,6 +552,7 @@ def inspect_window(hwnd: HWND, file=sys.stdout):
print("is_app_window:", is_app_window(hwnd), file=file)
print("is_manageable:", is_manageable_window(hwnd), file=file)
print("is_evelated :", window.is_evelated, file=file)
print("dpi_awareness:", window.dpi_awareness.name, file=file)


def inspect_active_window():
Expand Down
8 changes: 7 additions & 1 deletion src/jigsawwm/wm/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from jigsawwm.tiler.tilers import *
from jigsawwm.w32.monitor import Monitor, get_monitor_from_window
from jigsawwm.w32.window import RECT, Window, get_active_window
from jigsawwm.w32.process import ProcessDpiAwareness

from .theme import Theme

Expand Down Expand Up @@ -146,6 +147,12 @@ def arrange(self, theme: Optional[Theme] = None):
rect = RECT(left, top, right, bottom)
logger.debug("arrange %s %s", window, rect)
window.set_rect(rect)
i += 1
if window.dpi_awareness == ProcessDpiAwareness.PROCESS_DPI_UNAWARE:
# seems like the `get_extended_frame_bounds` would return physical size
# for DPI unware window, skip them for now
# TODO: convert physical size to logical size for DPI unware window
continue
# compensation
r = window.get_rect()
b = window.get_extended_frame_bounds()
Expand All @@ -156,7 +163,6 @@ def arrange(self, theme: Optional[Theme] = None):
round(bottom + r.bottom - b.bottom),
)
window.set_rect(RECT(*compensated_rect))
i += 1

def restrict(self, theme: Optional[Theme] = None):
"""Restrict all managed windows to their specified rect"""
Expand Down

0 comments on commit 8b92624

Please sign in to comment.