macos: add clamp helper to keep rectangle in workarea

This helper is useful to ensure we are consistent with how we keep a
window clamped to the workarea of a monitor when placing windows on
screen. (This does not affect snap-to-edges).
This commit is contained in:
Christian Hergert 2022-03-02 00:34:27 -08:00
parent 8c0df66d5f
commit 27b87ebec5
3 changed files with 37 additions and 32 deletions

View File

@ -20,7 +20,7 @@
#include "config.h" #include "config.h"
#include "gdkmacosdisplay-private.h" #include "gdkmacosdisplay-private.h"
#include "gdkmacosmonitor.h" #include "gdkmacosmonitor-private.h"
#include "gdkmacossurface-private.h" #include "gdkmacossurface-private.h"
#include "gdkmacostoplevelsurface-private.h" #include "gdkmacostoplevelsurface-private.h"
@ -36,47 +36,28 @@ _gdk_macos_display_position_toplevel_with_parent (GdkMacosDisplay *self,
{ {
GdkRectangle surface_rect; GdkRectangle surface_rect;
GdkRectangle parent_rect; GdkRectangle parent_rect;
GdkRectangle workarea;
GdkMonitor *monitor; GdkMonitor *monitor;
g_assert (GDK_IS_MACOS_DISPLAY (self)); g_assert (GDK_IS_MACOS_DISPLAY (self));
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface)); g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (surface));
g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (parent)); g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (parent));
/* If x/y is set, we should place relative to parent */ monitor = _gdk_macos_surface_get_best_monitor (parent);
if (GDK_SURFACE (surface)->x != 0 || GDK_SURFACE (surface)->y != 0)
{
*x = parent->root_x + GDK_SURFACE (surface)->x;
*y = parent->root_y + GDK_SURFACE (surface)->y;
return;
}
/* Try to center on top of the parent but also try to make the whole thing /* Try to center on top of the parent but also try to make the whole thing
* visible in case that lands us under the topbar/panel/etc. * visible in case that lands us under the topbar/panel/etc.
*/ */
surface_rect.x = surface->root_x + surface->shadow_left; parent_rect.x = parent->root_x + parent->shadow_left;
surface_rect.y = surface->root_y + surface->shadow_top; parent_rect.y = parent->root_y + parent->shadow_top;
parent_rect.width = GDK_SURFACE (parent)->width - parent->shadow_left - parent->shadow_right;
parent_rect.height = GDK_SURFACE (parent)->height - parent->shadow_top - parent->shadow_bottom;
surface_rect.width = GDK_SURFACE (surface)->width - surface->shadow_left - surface->shadow_right; surface_rect.width = GDK_SURFACE (surface)->width - surface->shadow_left - surface->shadow_right;
surface_rect.height = GDK_SURFACE (surface)->height - surface->shadow_top - surface->shadow_bottom; surface_rect.height = GDK_SURFACE (surface)->height - surface->shadow_top - surface->shadow_bottom;
parent_rect.x = parent->root_x + surface->shadow_left;
parent_rect.y = parent->root_y + surface->shadow_top;
parent_rect.width = GDK_SURFACE (parent)->width - surface->shadow_left - surface->shadow_right;
parent_rect.height = GDK_SURFACE (parent)->height - surface->shadow_top - surface->shadow_bottom;
/* Try to place centered atop parent */
surface_rect.x = parent_rect.x + ((parent_rect.width - surface_rect.width) / 2); surface_rect.x = parent_rect.x + ((parent_rect.width - surface_rect.width) / 2);
surface_rect.y = parent_rect.y + ((parent_rect.height - surface_rect.height) / 2); surface_rect.y = parent_rect.y + ((parent_rect.height - surface_rect.height) / 2);
/* Now make sure that we don't overlap the top-bar */ _gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (monitor), &surface_rect);
monitor = _gdk_macos_surface_get_best_monitor (parent);
gdk_macos_monitor_get_workarea (monitor, &workarea);
if (surface_rect.x < workarea.x)
surface_rect.x = workarea.x;
if (surface_rect.y < workarea.y)
surface_rect.y = workarea.y;
*x = surface_rect.x - surface->shadow_left; *x = surface_rect.x - surface->shadow_left;
*y = surface_rect.y - surface->shadow_top; *y = surface_rect.y - surface->shadow_top;
@ -123,11 +104,7 @@ _gdk_macos_display_position_toplevel (GdkMacosDisplay *self,
surface_rect.x = workarea.x + ((workarea.width - surface_rect.width) / 2); surface_rect.x = workarea.x + ((workarea.width - surface_rect.width) / 2);
surface_rect.y = workarea.y + ((workarea.height - surface_rect.height) / 2); surface_rect.y = workarea.y + ((workarea.height - surface_rect.height) / 2);
if (surface_rect.x < workarea.x) _gdk_macos_monitor_clamp (GDK_MACOS_MONITOR (surface->best_monitor), &surface_rect);
surface_rect.x = workarea.x;
if (surface_rect.y < workarea.y)
surface_rect.y = workarea.y;
*x = surface_rect.x - surface->shadow_left; *x = surface_rect.x - surface->shadow_left;
*y = surface_rect.y - surface->shadow_top; *y = surface_rect.y - surface->shadow_top;

View File

@ -41,6 +41,8 @@ void _gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *
GdkMacosSurface *surface); GdkMacosSurface *surface);
void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self, void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
GdkMacosSurface *surface); GdkMacosSurface *surface);
void _gdk_macos_monitor_clamp (GdkMacosMonitor *self,
GdkRectangle *area);
G_END_DECLS G_END_DECLS

View File

@ -431,3 +431,29 @@ _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
gdk_display_link_source_pause (self->display_link); gdk_display_link_source_pause (self->display_link);
} }
} }
void
_gdk_macos_monitor_clamp (GdkMacosMonitor *self,
GdkRectangle *area)
{
GdkRectangle workarea;
GdkRectangle geom;
g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
g_return_if_fail (area != NULL);
gdk_macos_monitor_get_workarea (GDK_MONITOR (self), &workarea);
gdk_monitor_get_geometry (GDK_MONITOR (self), &geom);
if (area->x + area->width > workarea.x + workarea.width)
area->x = workarea.x + workarea.width - area->width;
if (area->x < workarea.x)
area->x = workarea.x;
if (area->y + area->height > workarea.y + workarea.height)
area->y = workarea.y + workarea.height - area->height;
if (area->y < workarea.y)
area->y = workarea.y;
}