diff --git a/lib/awful/screen.lua b/lib/awful/screen.lua index f64e13fcd..5fff4f0f3 100644 --- a/lib/awful/screen.lua +++ b/lib/awful/screen.lua @@ -26,24 +26,42 @@ data.padding = {} screen.mouse_per_screen = {} +-- @param s Screen number +-- @param x X coordinate of point +-- @param y Y coordinate of point +-- @return The squared distance of the screen to the provided point +function screen.getdistance_sq(s, x, y) + local geom = capi.screen[s].geometry + local dist_x, dist_y = 0, 0 + if x < geom.x then + dist_x = geom.x - x + elseif x >= geom.x + geom.width then + dist_x = x - geom.x - geom.width + end + if y < geom.y then + dist_y = geom.y - y + elseif y >= geom.y + geom.height then + dist_y = y - geom.y - geom.height + end + return dist_x * dist_x + dist_y * dist_y +end + --- -- Return Xinerama screen number corresponding to the given (pixel) coordinates. -- The number returned can be used as an index into the global -- `screen` table/object. -- @param x The x coordinate -- @param y The y coordinate --- @param[opt] default The default return value. If unspecified, 1 is returned. -function screen.getbycoord(x, y, default) - for i = 1, capi.screen:count() do - local geometry = capi.screen[i].geometry - if((x < 0 or (x >= geometry.x and x < geometry.x + geometry.width)) - and (y < 0 or (y >= geometry.y and y < geometry.y + geometry.height))) then - return i +function screen.getbycoord(x, y) + local s = 1 + local dist = screen.getdistance_sq(s, x, y) + for i = 2, capi.screen:count() do + local d = screen.getdistance_sq(i, x, y) + if d < dist then + s, dist = i, d end end - -- No caller expects a nil result here, so just make something up - if default == nil then return 1 end - return default + return s end --- Give the focus to a screen, and move pointer to last known position on this diff --git a/objects/screen.c b/objects/screen.c index 4ec161c8e..57be3561b 100644 --- a/objects/screen.c +++ b/objects/screen.c @@ -35,7 +35,6 @@ #include "objects/client.h" #include "objects/drawin.h" -#include #include #include @@ -285,6 +284,38 @@ screen_scan(void) screen_scan_x11(); } +/** Return the squared distance of the given screen to the coordinates. + * \param screen The screen + * \param x X coordinate + * \param y Y coordinate + * \return Squared distance of the point to the screen. + */ +static unsigned int +screen_get_distance_squared(screen_t *s, int x, int y) +{ + int sx = s->geometry.x, sy = s->geometry.y; + int sheight = s->geometry.height, swidth = s->geometry.width; + unsigned int dist_x, dist_y; + + /* Calculate distance in X coordinate */ + if (x < sx) + dist_x = sx - x; + else if (x < sx + swidth) + dist_x = 0; + else + dist_x = x - sx - swidth; + + /* Calculate distance in Y coordinate */ + if (y < sy) + dist_y = sy - y; + else if (y < sy + sheight) + dist_y = 0; + else + dist_y = y - sy - sheight; + + return dist_x * dist_x + dist_y * dist_y; +} + /** Return the first screen number where the coordinates belong to. * \param x X coordinate * \param y Y coordinate @@ -298,15 +329,15 @@ screen_getbycoord(int x, int y) return *s; /* No screen found, find nearest screen. */ - screen_t * nearest_screen = globalconf.screens.tab[0]; - int nearest_dist = INT_MAX; + screen_t *nearest_screen = globalconf.screens.tab[0]; + unsigned int nearest_dist = UINT_MAX; foreach(s, globalconf.screens) { - int dist = sqrt(pow((*s)->geometry.x - x, 2) + pow((*s)->geometry.y - y, 2)); - if( dist < nearest_dist ) + unsigned int dist_sq = screen_get_distance_squared(*s, x, y); + if(dist_sq < nearest_dist) { - nearest_dist = dist; - nearest_screen = (*s); + nearest_dist = dist_sq; + nearest_screen = *s; } } return nearest_screen;