Skip to content

Commit

Permalink
fix: transpose selected region correctly #397
Browse files Browse the repository at this point in the history
On wayland, window and screen dimensions reported by Qt differ if
"normal" scaling is used, or the experimental fractional scaling
(scale-monitor-framebuffer). To transpose the selected region from
window position to screenshot position robustly, it's better to use
Qt's window dimensions as reference instead of the Qt's screen
dimensions.
  • Loading branch information
dynobo committed Dec 4, 2023
1 parent dc8fced commit 98691bc
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 10 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Changelog

## v0.5.0beta2 (not yet released)
## v0.5.0 (not yet released)

- All: Fix issue where introduction window was still visible on the screen capture UI.
([#536 comment](https://github.com/dynobo/normcap/issues/536#issuecomment-1752110232))
Expand All @@ -16,6 +16,10 @@
replaced by `"`. (You can still use "raw"-mode to leave them intact.)
- Windows, macOS: Fix notifications not clickable in "raw"-Mode.
([#438 comment](https://github.com/dynobo/normcap/issues/438#issuecomment-1752175090))
- Linux: Fig segfault in AppImage.
([#543](https://github.com/dynobo/normcap/issues/534))
- Linux: Fix incorrect selection when display scaling is active.
([#397](https://github.com/dynobo/normcap/issues/397))
- Linux: Add support for using `xclip` to copy result to clipboard. This seems more
stable on Wayland systems than `wl-clipboard`, at least until compatibility with
latest Gnome updates is restored.
Expand Down
14 changes: 9 additions & 5 deletions normcap/gui/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
import logging
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Callable, NamedTuple, cast
from typing import Any, Callable, cast

from PySide6 import QtCore, QtGui, QtWidgets

Expand All @@ -33,7 +34,8 @@
logger = logging.getLogger(__name__)


class DebugInfo(NamedTuple):
@dataclass
class DebugInfo:
screen: Screen | None = None
window: QtWidgets.QMainWindow | None = None
scale_factor: float = 1
Expand Down Expand Up @@ -166,7 +168,7 @@ def _get_scale_factor(self) -> float:
"""Calculate scale factor from image and screen dimensions."""
if not self.screen_.screenshot:
raise ValueError("Screenshot image is missing!")
return self.screen_.screenshot.width() / self.screen_.width
return self.screen_.screenshot.width() / self.width()

def _add_image_container(self) -> None:
"""Add widget showing screenshot."""
Expand Down Expand Up @@ -338,6 +340,8 @@ def resizeEvent(self, event: QtGui.QResizeEvent) -> None: # noqa: N802
"""Adjust child widget on resize."""
super().resizeEvent(event)
self.ui_container.resize(self.size())
if self.ui_container.debug_info:
self.ui_container.debug_info.scale_factor = self._get_scale_factor()

def showEvent(self, event: QtGui.QShowEvent) -> None: # noqa: N802
"""Update background image on show/reshow."""
Expand Down Expand Up @@ -386,17 +390,17 @@ def _draw_debug_infos(self, painter: QtGui.QPainter, rect: QtCore.QRect) -> None
"[ Screen ]",
f"Size: {self.debug_info.screen.size}",
f"Position: {self.debug_info.screen.coords}",
f"Selected region: {selection.geometry}",
f"Device pixel ratio: {self.debug_info.screen.device_pixel_ratio}",
"",
"[ Window ]",
f"Size: {self.debug_info.window.size().toTuple()}",
f"Position: {cast(tuple, self.debug_info.window.geometry().getCoords())}",
f"Device pixel ratio: {self.debug_info.window.devicePixelRatio()}",
f"Selected region: {selection.coords}",
"",
"[ Screenshot ]",
f"Size: {self.debug_info.screen.screenshot.size().toTuple()}",
f"Selected region (scaled): {selection_scaled.geometry}",
f"Selected region (scaled): {selection_scaled.coords}",
"",
"[ Scaling detected ]",
f"Factor: {self.debug_info.scale_factor:.2f}",
Expand Down
9 changes: 5 additions & 4 deletions tests/tests_gui/test_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ def test_move_active_window_to_position_raises_on_non_linux():

@pytest.mark.gui()
@pytest.mark.parametrize(
("img_size", "screen_size", "expected_factor"),
("img_size", "window_size", "expected_factor"),
[
((600, 400), (600, 400), 1.0),
((300, 200), (600, 400), 0.5),
((1200, 800), (600, 400), 2.0),
],
)
def test_window_get_scale_factor(
qtbot, temp_settings, img_size, screen_size, expected_factor
qtbot, temp_settings, img_size, window_size, expected_factor
):
# GIVEN a screenshot of a certain size
# and a certain (Qt) screen size
Expand All @@ -42,14 +42,15 @@ def test_window_get_scale_factor(
device_pixel_ratio=1.0,
left=0,
top=0,
right=screen_size[0] - 1,
bottom=screen_size[1] - 1,
right=window_size[0] - 1,
bottom=window_size[1] - 1,
index=0,
screenshot=image,
)

# WHEN the window is shown
win = window.Window(screen=screen, settings=temp_settings, parent=None)
win.resize(QtCore.QSize(*window_size))
qtbot.addWidget(win)

# THEN the expected scaling factor should be calculated
Expand Down

0 comments on commit 98691bc

Please sign in to comment.