Skip to content

Commit

Permalink
New approach based on Monitor() class to access all properties and fu…
Browse files Browse the repository at this point in the history
…nctionalities. macOS is still experimental and not tested on multi-monitor setups.
  • Loading branch information
Kalmat committed Jul 19, 2023
1 parent 37f2298 commit 8552df7
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 91 deletions.
22 changes: 15 additions & 7 deletions TODO.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
General:
- Include more functions to control monitors
- Resolution
- Scale
- Orientation
- Position
- others (?)
LINUX
- setPosition must be invoked twice???
- Find a proper way to detach/attach monitors
- Find alternative to suspend monitor
- Is there a way to properly calculate WORKAREA??? (https://askubuntu.com/questions/1124149/how-to-get-taskbar-size-and-position-with-python)

WINDOWS
- Find a solution for changing scale

MACOS
- Contact display-manager-lib team to check alternatives or find another solution (for setOrientation, brightness)
- Test everything in an actual macOS installation with a multi-monitor setup
- Check returned coordinates
- Find a way to turn monitor OFF/ON/SUSPEND/WAKEUP/DETACH/ATTACH
- Investigate all other methods (contrast, scale, isOn)
Binary file modified dist/PyMonCtl-0.0.9-py3-none-any.whl
Binary file not shown.
34 changes: 17 additions & 17 deletions src/pymonctl/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,39 +696,39 @@ def _getRelativePosition(monitor, relativeTo) -> Tuple[int, int, str]:
x = y = 0
cmd = ""
elif relPos == Position.LEFT_TOP:
x = relativeTo["pos"].x - monitor["size"].width
y = relativeTo["pos"].y
x = relativeTo["position"].x - monitor["size"].width
y = relativeTo["position"].y
cmd = " --left-of %s"
elif relPos == Position.LEFT_BOTTOM:
x = relativeTo["pos"].x - monitor["size"].width
y = relativeTo["pos"].y + relativeTo["size"].height - monitor["size"].height
x = relativeTo["position"].x - monitor["size"].width
y = relativeTo["position"].y + relativeTo["size"].height - monitor["size"].height
cmd = " --left-of %s"
elif relPos == Position.ABOVE_LEFT:
x = relativeTo["pos"].x
y = relativeTo["pos"].y - monitor["size"].height
x = relativeTo["position"].x
y = relativeTo["position"].y - monitor["size"].height
cmd = " --above %s"
elif relPos == Position.ABOVE_RIGHT:
x = relativeTo["pos"].x + relativeTo["size"].width - monitor["size"].width
y = relativeTo["pos"].y - monitor["size"].height
x = relativeTo["position"].x + relativeTo["size"].width - monitor["size"].width
y = relativeTo["position"].y - monitor["size"].height
cmd = " --above %s"
elif relPos == Position.RIGHT_TOP:
x = relativeTo["pos"].x + relativeTo["size"].width
y = relativeTo["pos"].y
x = relativeTo["position"].x + relativeTo["size"].width
y = relativeTo["position"].y
cmd = " --right-of %s"
elif relPos == Position.RIGHT_BOTTOM:
x = relativeTo["pos"].x + relativeTo["size"].width
y = relativeTo["pos"].y + relativeTo["size"].height - monitor["size"].height
x = relativeTo["position"].x + relativeTo["size"].width
y = relativeTo["position"].y + relativeTo["size"].height - monitor["size"].height
cmd = " --right-of %s"
elif relPos == Position.BELOW_LEFT:
x = relativeTo["pos"].x
y = relativeTo["pos"].y + relativeTo["size"].height
x = relativeTo["position"].x
y = relativeTo["position"].y + relativeTo["size"].height
cmd = " --below %s"
elif relPos == Position.BELOW_RIGHT:
x = relativeTo["pos"].x + relativeTo["size"].width - monitor["size"].width
y = relativeTo["pos"].y + relativeTo["size"].height
x = relativeTo["position"].x + relativeTo["size"].width - monitor["size"].width
y = relativeTo["position"].y + relativeTo["size"].height
cmd = " --below %s"
else:
x = y = monitor["pos"]
x = y = monitor["position"]
cmd = ""
return x, y, cmd

Expand Down
60 changes: 30 additions & 30 deletions src/pymonctl/_pymonctl_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def setScale(self, scale: Tuple[float, float]):
if scale is not None:
# https://askubuntu.com/questions/1193940/setting-monitor-scaling-to-200-with-xrandr
scaleX, scaleY = scale
cmd = " --scale %sx%s --filter nearest" % (scaleX, scaleY)
cmd = " --filter nearest --scale %sx%s" % (scaleX, scaleY)
if self.name and self.name in _XgetAllMonitorsNames():
cmd = (" --output %s" % self.name) + cmd
cmd = "xrandr" + cmd
Expand Down Expand Up @@ -280,30 +280,30 @@ def orientation(self) -> Optional[Union[int, Orientation]]:

def setOrientation(self, orientation: Optional[Union[int, Orientation]]):
if orientation in (NORMAL, INVERTED, LEFT, RIGHT):
outputs = _XgetAllOutputs(self.name)
for outputData in outputs:
display, screen, root, res, output, outputInfo = outputData
crtcInfo = randr.get_crtc_info(display, outputInfo.crtc, Xlib.X.CurrentTime)
if crtcInfo and crtcInfo.mode:
randr.set_crtc_config(display, outputInfo.crtc, Xlib.X.CurrentTime, crtcInfo.x, crtcInfo.y,
crtcInfo.mode, (orientation or 1) ** 2, crtcInfo.outputs)

# if orientation == RIGHT:
# direction = "right"
# elif orientation == INVERTED:
# direction = "inverted"
# elif orientation == LEFT:
# direction = "left"
# else:
# direction = "normal"
# cmd = " -o %s" % direction
# if name and name in __getMonitorsNames():
# cmd = (" --output %s" % name) + cmd
# cmd = "xrandr" + cmd
# try:
# subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL)
# except:
# pass
# outputs = _XgetAllOutputs(self.name)
# for outputData in outputs:
# display, screen, root, res, output, outputInfo = outputData
# crtcInfo = randr.get_crtc_info(display, outputInfo.crtc, Xlib.X.CurrentTime)
# if crtcInfo and crtcInfo.mode:
# randr.set_crtc_config(display, outputInfo.crtc, Xlib.X.CurrentTime, crtcInfo.x, crtcInfo.y,
# crtcInfo.mode, (orientation or 1) ** 2, crtcInfo.outputs)

if orientation == RIGHT:
direction = "right"
elif orientation == INVERTED:
direction = "inverted"
elif orientation == LEFT:
direction = "left"
else:
direction = "normal"
cmd = " -o %s" % direction
if self.name in _XgetAllMonitorsNames():
cmd = (" --output %s" % self.name) + cmd
cmd = "xrandr" + cmd
try:
subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL)
except:
pass

@property
def frequency(self) -> Optional[float]:
Expand Down Expand Up @@ -360,7 +360,6 @@ def brightness(self) -> Optional[int]:
# 'Brightness')

def setBrightness(self, brightness: Optional[int]):
# https://unix.stackexchange.com/questions/150816/how-can-i-lazily-read-output-from-xrandr
if brightness is not None:
value = brightness / 100
if 0 <= value <= 1:
Expand Down Expand Up @@ -578,7 +577,7 @@ def _setPrimary(name: str):


def _setPositionTwice(relativePos: Position, relativeTo: Optional[str], name: str):
# Why it has to be invoked twice? Perhaps there is an option to commit changes?
# Why it has to be invoked twice? Perhaps there is an option to commit changes?
_setPositionTwice(relativePos, relativeTo, name)
time.sleep(0.5)
_setPositionTwice(relativePos, relativeTo, name)
Expand All @@ -594,16 +593,17 @@ def _setPosition(relativePos: Position, relativeTo: Optional[str], name: str):

targetMonInfo = monitors[name]["monitor"]
targetMon = {"relativePos": relativePos, "relativeTo": relativeTo,
"pos": Point(targetMonInfo.x, targetMonInfo.y),
"position": Point(targetMonInfo.x, targetMonInfo.y),
"size": Size(targetMonInfo.width_in_pixels, targetMonInfo.height_in_pixels)}

relMonInfo = monitors[relativeTo]["monitor"]
relMon = {"pos": Point(relMonInfo.x, relMonInfo.y),
relMon = {"position": Point(relMonInfo.x, relMonInfo.y),
"size": Size(relMonInfo.width_in_pixels, relMonInfo.height_in_pixels)}

primaryName = _getPrimaryName()
# WARNING: There will be no primary monitor when moving it to another position!
cmd2 = " --noprimary" if name == primaryName else ""
# cmd2 = " --noprimary" if name == primaryName else ""
cmd2 = ""
x, y, relCmd = _getRelativePosition(targetMon, relMon)
cmd3 = relCmd % relativeTo if relativePos in (LEFT_TOP, RIGHT_TOP, ABOVE_LEFT, BELOW_LEFT) else ""
cmd = ("xrandr --output %s --pos %sx%s" % (name, x, y)) + cmd2 + cmd3
Expand Down
Loading

0 comments on commit 8552df7

Please sign in to comment.