]> Dogcows Code - chaz/openbox/commitdiff
Use the nearest monitor when the search query rect does not intersect any monitor...
authorDana Jansens <danakj@orodu.net>
Mon, 1 Oct 2012 00:29:45 +0000 (20:29 -0400)
committerDana Jansens <danakj@orodu.net>
Sun, 7 Oct 2012 01:56:56 +0000 (21:56 -0400)
Previously we would try to find the primary monitor and use that when the search
was outside any monitor. However, if the primary monitor is chosen by the mouse
position and the mouse is not inside any monitor, we enter infinite recursion
trying to find the primary monitor.

The nearest monitor is a better metric anyhow, and this ensures
screen_find_monitor() is never recursive as it always returns a value without
depending on other screen.c methods.

openbox/geom.h
openbox/screen.c

index 8ac0e550830980d4ea05f612389155278cb891ce..8e50834bc7084420e79840b09b02577ae5630a18 100644 (file)
@@ -104,6 +104,25 @@ typedef struct _Rect {
      (r).height = MIN((a).y + (a).height - 1, \
                       (b).y + (b).height - 1) - (r).y + 1)
 
+/* Returns the shortest manhatten distance between two rects, or 0 if they
+   intersect. */
+static inline gint rect_manhatten_distance(Rect r, Rect o)
+{
+    if (RECT_INTERSECTS_RECT(r, o))
+        return 0;
+
+    gint min_distance = G_MAXINT;
+    if (RECT_RIGHT(o) < RECT_LEFT(r))
+        min_distance = MIN(min_distance, RECT_LEFT(r) - RECT_RIGHT(o));
+    if (RECT_LEFT(o) > RECT_RIGHT(r))
+        min_distance = MIN(min_distance, RECT_LEFT(o) - RECT_RIGHT(r));
+    if (RECT_BOTTOM(o) < RECT_TOP(r))
+        min_distance = MIN(min_distance, RECT_TOP(r) - RECT_BOTTOM(o));
+    if (RECT_TOP(o) > RECT_BOTTOM(r))
+        min_distance = MIN(min_distance, RECT_TOP(o) - RECT_BOTTOM(r));
+    return min_distance;
+}
+
 typedef struct _Strut {
     int left;
     int top;
index 35366beb9cca0584becddda63d342682889e1e30..f4031f59591cf430edd1b93eaddcc7130c80536b 100644 (file)
@@ -1644,8 +1644,10 @@ typedef struct {
 guint screen_find_monitor(const Rect *search)
 {
     guint i;
-    guint most = screen_num_monitors;
+    guint mostpx_index = screen_num_monitors;
     guint mostpx = 0;
+    guint closest_distance_index = screen_num_monitors;
+    guint closest_distance = G_MAXUINT;
     GSList *counted = NULL;
 
     /* we want to count the number of pixels search has on each monitor, but not
@@ -1686,7 +1688,7 @@ guint screen_find_monitor(const Rect *search)
 
             if (area > mostpx) {
                 mostpx = area;
-                most = config_primary_monitor_index;
+                mostpx_index = config_primary_monitor_index;
             }
 
             /* add the intersection rect on the current monitor to the
@@ -1709,10 +1711,21 @@ guint screen_find_monitor(const Rect *search)
 
         monitor = screen_physical_area_monitor(i);
 
+        if (!RECT_INTERSECTS_RECT(*monitor, *search)) {
+            /* If we don't intersect then find the distance between the search
+               rect and the monitor. We'll use the closest monitor from this
+               metric if none of the monitors intersect. */
+            guint distance = rect_manhatten_distance(*monitor, *search);
+
+            if (distance < closest_distance) {
+                closest_distance = distance;
+                closest_distance_index = i;
+            }
+            continue;
+        }
+
         if (i == config_primary_monitor_index)
             continue;  /* already did this one */
-        if (!RECT_INTERSECTS_RECT(*monitor, *search))
-            continue;  /* nothing to see here */
 
         RECT_SET_INTERSECTION(on_current_monitor, *monitor, *search);
         area = RECT_AREA(on_current_monitor);
@@ -1729,7 +1742,7 @@ guint screen_find_monitor(const Rect *search)
 
         if (area > mostpx) {
             mostpx = area;
-            most = i;
+            mostpx_index = i;
         }
 
         /* add the intersection rect on the current monitor I to the counted
@@ -1765,7 +1778,11 @@ guint screen_find_monitor(const Rect *search)
         counted = g_slist_delete_link(counted, counted);
     }
 
-    return most < screen_num_monitors ? most : screen_monitor_primary(FALSE);
+    if (mostpx_index < screen_num_monitors)
+        return mostpx_index;
+
+    g_assert(closest_distance_index < screen_num_monitors);
+    return closest_distance_index;
 }
 
 const Rect* screen_physical_area_all_monitors(void)
This page took 0.031973 seconds and 4 git commands to generate.