Repository: AlexisBRENON/ewmh_m2m

Issue:
No sibling screen found - Error
Thanks for the great script! Unfortunately this is what I get:

    $ move-to-monitor -v -v
    DEBUG:ewmh_m2m.__main__:Detected screens: {Geometry(2960, 0, 1920, 1200), Geometry(0, 176, 1280, 1024), Geometry(1280, 150, 1680, 1050)}
    DEBUG:ewmh_m2m.__main__:Containing screen: Geometry(0, 176, 1280, 1024)
    CRITICAL:ewmh_m2m.__main__:No sibling screen found

This is my screen configuration:
![image](https://user-images.githubusercontent.com/3918330/72931928-08614000-3d5f-11ea-9e82-6182ba5e399d.png)


Any suggestions?

Discussion:

Patch:
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
index 49e0dde..e6b449e 100644
--- a/.github/workflows/python.yml
+++ b/.github/workflows/python.yml
@@ -19,7 +19,7 @@ jobs:
       - name: Set up pip
         run: |
           python -m pip install --upgrade pip
-          pip install --upgrade setuptools
+          pip install --upgrade setuptools wheel
       - name: Install
         run: pip install '.[testing]'
       - name: Test with pytest
@@ -38,7 +38,7 @@ jobs:
       - name: Set up pip
         run: |
           python -m pip install --upgrade pip
-          pip install --upgrade setuptools
+          pip install --upgrade setuptools wheel
       - name: Install
         run: pip install '.[releasing]'
       - name: Build
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 9bc9eb1..3dbbed3 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,11 @@
 Changelog
 =========
 
+Version 1.1.3
+=============
+
+- Detect siblings screens even if not aligned with the current one
+
 Version 1.1.2
 =============
 
diff --git a/src/ewmh_m2m/geometry.py b/src/ewmh_m2m/geometry.py
index 7751d48..706fbf8 100644
--- a/src/ewmh_m2m/geometry.py
+++ b/src/ewmh_m2m/geometry.py
@@ -30,6 +30,15 @@ class Geometry:
             y=int(container.y + self.y * container.h)
         )
 
+    def horizontally_overlap(self, other) -> bool:
+        return self.y < other.y + other.h and self.y + self.h > other.y
+
+    def vertically_overlap(self, other) -> bool:
+        return self.x < other.x + other.w and self.x + self.w > other.x
+
+    def overlap(self, other) -> bool:
+        return self.horizontally_overlap(other) and self.vertically_overlap(other)
+
     def __eq__(self, other):
         return list(self) == list(other)
 
diff --git a/src/ewmh_m2m/screen.py b/src/ewmh_m2m/screen.py
index e9e340b..d2f050f 100644
--- a/src/ewmh_m2m/screen.py
+++ b/src/ewmh_m2m/screen.py
@@ -17,8 +17,8 @@ def get_sibling_screens(current: Geometry, screens: Iterable[Geometry]) -> Dict[
 
     Each list is ordered from the nearest screen to the furthest one.
     """
-    horizontal_screens = [g for g in screens if g.y == current.y]
-    vertical_screens = [g for g in screens if g.x == current.x]
+    horizontal_screens = [g for g in screens if current.horizontally_overlap(g)]
+    vertical_screens = [g for g in screens if current.vertically_overlap(g)]
     return {
         Ordinal.SOUTH: sorted([g for g in vertical_screens if g.y > current.y], key=lambda g: g.y),
         Ordinal.NORTH: sorted([g for g in vertical_screens if g.y < current.y], key=lambda g: -1 * g.y),


Test patch:
diff --git a/tests/test_geometry.py b/tests/test_geometry.py
new file mode 100644
index 0000000..3b058b6
--- /dev/null
+++ b/tests/test_geometry.py
@@ -0,0 +1,49 @@
+from ewmh_m2m.geometry import Geometry
+
+
+class TestGeometry:
+
+    def test_horizontally_not_overlap(self):
+        g1 = Geometry(0, 0, 1, 1)
+        g2 = Geometry(10, 10, 1, 1)
+
+        assert not g1.horizontally_overlap(g2)
+        assert not g2.horizontally_overlap(g1)
+
+    def test_horizontally_overlap(self):
+        g1 = Geometry(0, 0, 10, 10)
+        g2 = Geometry(100, 0, 10, 10)
+
+        assert g1.horizontally_overlap(g2)
+        assert g2.horizontally_overlap(g1)
+
+    def test_vertically_not_overlap(self):
+        g1 = Geometry(0, 0, 10, 10)
+        g2 = Geometry(100, 100, 10, 10)
+
+        assert not g1.vertically_overlap(g2)
+        assert not g2.vertically_overlap(g1)
+
+    def test_vertically_overlap(self):
+        g1 = Geometry(0, 0, 10, 10)
+        g2 = Geometry(0, 100, 10, 10)
+
+        assert g1.vertically_overlap(g2)
+        assert g2.vertically_overlap(g1)
+
+    def test_not_overlap(self):
+        g1 = Geometry(0, 0, 10, 10)
+        g2 = Geometry(100, 0, 10, 10)
+        g3 = Geometry(0, 100, 10, 10)
+
+        assert not g1.overlap(g2)
+        assert not g2.overlap(g1)
+        assert not g1.overlap(g3)
+        assert not g3.overlap(g1)
+
+    def test_overlap(self):
+        g1 = Geometry(0, 0, 10, 10)
+        g2 = Geometry(1, 1, 8, 8)
+
+        assert g1.overlap(g2)
+        assert g2.overlap(g1)
diff --git a/tests/test_screen.py b/tests/test_screen.py
index 8e3502a..9ff1104 100644
--- a/tests/test_screen.py
+++ b/tests/test_screen.py
@@ -1,8 +1,6 @@
 # -*- coding: utf-8 -*-
 import random
 
-import pytest
-
 import ewmh_m2m.screen
 from ewmh_m2m.geometry import Geometry
 from ewmh_m2m.ordinal import Ordinal
@@ -73,6 +71,17 @@ class TestScreen:
             Ordinal.WEST: [Geometry(1, 2, 1, 1), Geometry(0, 2, 1, 1)]
         }
 
+    def test_siblings_gh_issue_14(self):
+        """
+        Inspired by issue 14: https://github.com/AlexisBRENON/ewmh_m2m/issues/14
+        """
+        screens = {Geometry(2960, 0, 1920, 1200), Geometry(0, 176, 1280, 1024), Geometry(1280, 150, 1680, 1050)}
+        current = Geometry(0, 176, 1280, 1024)
+
+        siblings = ewmh_m2m.screen.get_sibling_screens(current, screens)
+
+        assert siblings[Ordinal.EAST] == [Geometry(1280, 150, 1680, 1050), Geometry(2960, 0, 1920, 1200)]
+
     def test_sibling_nominal(self):
         siblings = {
             Ordinal.EAST: [Geometry(1, 0, 1, 1), Geometry(2, 0, 1, 1)]