forked from AuroraMiddleware/gtk
gdk/surface: Replace move_to_rect() with GdkPopupLayout based API
Replace the gdk_surface_move_to_rect() API with a new GdkSurface method called gdk_surface_present_popup() taking a new GdkPopupLayout object describing how they should be laid out on screen. The layout properties provided are the same as the ones used with gdk_surface_move_to_rect(), except they are now set up using GdkPopupLayout. Calling gdk_surface_present_popup() will either show the popup at the position described using the popup layout object and a new unconstrained size, or reposition it accordingly. In some situations, such as when a popup is set to autohide, presenting may immediately fail, in case the grab was not granted by the display server. After a successful present, the result of the layout can be queried using the following methods: * gdk_surface_get_position() - to get the position relative to its parent * gdk_surface_get_width() - to get the current width * gdk_surface_get_height() - to get the current height * gdk_surface_get_rect_anchor() - to get the anchor point on the anchor rectangle the popup was effectively positioned against given constraints defined by the environment and the layout rules provided via GdkPopupLayout. * gdk_surface_get_surface_anchor() - the same as the one above but for the surface anchor. A new signal replaces the old "moved-to-rect" one - "popup-layout-changed". However, it is only intended to be emitted when the layout changes implicitly by the windowing system, for example if the monitor resolution changed, or the parent window moved.
This commit is contained in:
parent
37f4c644d3
commit
ca71119a40
@ -205,7 +205,9 @@ gdk_surface_set_keep_above
|
||||
gdk_surface_set_keep_below
|
||||
gdk_surface_set_opacity
|
||||
gdk_surface_resize
|
||||
gdk_surface_move_to_rect
|
||||
gdk_surface_present_popup
|
||||
gdk_surface_get_popup_rect_anchor
|
||||
gdk_surface_get_popup_surface_anchor
|
||||
gdk_surface_raise
|
||||
gdk_surface_lower
|
||||
gdk_surface_restack
|
||||
|
@ -455,18 +455,21 @@ gdk_broadway_surface_move (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle final_rect)
|
||||
gdk_broadway_surface_layout_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
GdkSurface *toplevel;
|
||||
GdkRectangle final_rect;
|
||||
int x, y;
|
||||
|
||||
if (surface->surface_type == GDK_SURFACE_POPUP)
|
||||
toplevel = surface->parent;
|
||||
else
|
||||
toplevel = surface->transient_for;
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
layout,
|
||||
&final_rect);
|
||||
|
||||
gdk_surface_get_origin (toplevel, &x, &y);
|
||||
gdk_surface_get_origin (surface->parent, &x, &y);
|
||||
x += final_rect.x;
|
||||
y += final_rect.y;
|
||||
|
||||
@ -474,8 +477,10 @@ gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
|
||||
final_rect.height != surface->height)
|
||||
{
|
||||
gdk_broadway_surface_move_resize (surface,
|
||||
x, y,
|
||||
final_rect.width, final_rect.height);
|
||||
x,
|
||||
y,
|
||||
final_rect.width,
|
||||
final_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -484,22 +489,49 @@ gdk_broadway_surface_moved_to_rect (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_broadway_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
show_popup (GdkSurface *surface)
|
||||
{
|
||||
gdk_surface_move_to_rect_helper (surface,
|
||||
rect,
|
||||
rect_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy,
|
||||
gdk_broadway_surface_moved_to_rect);
|
||||
gdk_surface_raise (surface);
|
||||
gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
|
||||
_gdk_surface_update_viewable (surface);
|
||||
gdk_broadway_surface_show (surface, FALSE);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
show_grabbing_popup (GdkSeat *seat,
|
||||
GdkSurface *surface,
|
||||
gpointer user_data)
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_broadway_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
gdk_broadway_surface_layout_popup (surface, width, height, layout);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
return TRUE;
|
||||
|
||||
if (surface->autohide)
|
||||
{
|
||||
gdk_seat_grab (gdk_display_get_default_seat (surface->display),
|
||||
surface,
|
||||
GDK_SEAT_CAPABILITY_ALL,
|
||||
TRUE,
|
||||
NULL, NULL,
|
||||
show_grabbing_popup, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
return GDK_SURFACE_IS_MAPPED (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1393,7 +1425,7 @@ gdk_broadway_surface_class_init (GdkBroadwaySurfaceClass *klass)
|
||||
impl_class->lower = gdk_broadway_surface_lower;
|
||||
impl_class->restack_toplevel = gdk_broadway_surface_restack_toplevel;
|
||||
impl_class->toplevel_resize = gdk_broadway_surface_toplevel_resize;
|
||||
impl_class->move_to_rect = gdk_broadway_surface_move_to_rect;
|
||||
impl_class->present_popup = gdk_broadway_surface_present_popup;
|
||||
impl_class->get_geometry = gdk_broadway_surface_get_geometry;
|
||||
impl_class->get_root_coords = gdk_broadway_surface_get_root_coords;
|
||||
impl_class->get_device_state = gdk_broadway_surface_get_device_state;
|
||||
|
@ -35,6 +35,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkGLContext, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkKeymap, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkMonitor, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSeat, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkPopupLayout, gdk_popup_layout_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkVulkanContext, g_object_unref)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkSurface, g_object_unref)
|
||||
|
||||
|
281
gdk/gdkpopuplayout.c
Normal file
281
gdk/gdkpopuplayout.c
Normal file
@ -0,0 +1,281 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2020 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkpopuplayout.h"
|
||||
|
||||
#include "gdksurface.h"
|
||||
|
||||
struct _GdkPopupLayout
|
||||
{
|
||||
/* < private >*/
|
||||
grefcount ref_count;
|
||||
|
||||
GdkRectangle anchor_rect;
|
||||
GdkGravity rect_anchor;
|
||||
GdkGravity surface_anchor;
|
||||
GdkAnchorHints anchor_hints;
|
||||
int dx;
|
||||
int dy;
|
||||
|
||||
gboolean is_sealed;
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GdkPopupLayout, gdk_popup_layout,
|
||||
gdk_popup_layout_ref,
|
||||
gdk_popup_layout_unref)
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_new: (constructor)
|
||||
* @anchor_rect: (not nullable): the anchor #GdkRectangle to align @surface with
|
||||
* @rect_anchor: the point on @anchor_rect to align with @surface's anchor point
|
||||
* @surface_anchor: the point on @surface to align with @rect's anchor point
|
||||
*
|
||||
* Create a popup layout description. Used together with
|
||||
* gdk_surface_present_popup() to describe how a popup surface should be placed
|
||||
* and behave on-screen.
|
||||
*
|
||||
* @anchor_rect is relative to the top-left corner of the surface's parent.
|
||||
* @rect_anchor and @surface_anchor determine anchor points on @anchor_rect and
|
||||
* surface to pin together.
|
||||
*
|
||||
* The position of @anchor_rect's anchor point can optionally be offset using
|
||||
* gdk_popup_layout_set_offset(), which is equivalent to offsetting the
|
||||
* position of surface.
|
||||
*
|
||||
* Returns: (transfer full): newly created instance of #GdkPopupLayout
|
||||
*/
|
||||
GdkPopupLayout *
|
||||
gdk_popup_layout_new (const GdkRectangle *anchor_rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor)
|
||||
{
|
||||
GdkPopupLayout *layout;
|
||||
|
||||
layout = g_new0 (GdkPopupLayout, 1);
|
||||
g_ref_count_init (&layout->ref_count);
|
||||
layout->anchor_rect = *anchor_rect;
|
||||
layout->rect_anchor = rect_anchor;
|
||||
layout->surface_anchor = surface_anchor;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_ref:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Increases the reference count of @value.
|
||||
*
|
||||
* Returns: the same @layout
|
||||
*/
|
||||
GdkPopupLayout *
|
||||
gdk_popup_layout_ref (GdkPopupLayout *layout)
|
||||
{
|
||||
g_ref_count_inc (&layout->ref_count);
|
||||
return layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_unref:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Decreases the reference count of @value.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_unref (GdkPopupLayout *layout)
|
||||
{
|
||||
if (g_ref_count_dec (&layout->ref_count))
|
||||
g_free (layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_copy:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Create a new #GdkPopupLayout and copy the contents of @layout into it.
|
||||
*
|
||||
* Returns: (transfer full): a copy of @layout.
|
||||
*/
|
||||
GdkPopupLayout *
|
||||
gdk_popup_layout_copy (GdkPopupLayout *layout)
|
||||
{
|
||||
GdkPopupLayout *new_layout;
|
||||
|
||||
new_layout = g_new0 (GdkPopupLayout, 1);
|
||||
g_ref_count_init (&new_layout->ref_count);
|
||||
|
||||
new_layout->anchor_rect = layout->anchor_rect;
|
||||
new_layout->rect_anchor = layout->rect_anchor;
|
||||
new_layout->surface_anchor = layout->surface_anchor;
|
||||
new_layout->anchor_hints = layout->anchor_hints;
|
||||
new_layout->dx = layout->dx;
|
||||
new_layout->dy = layout->dy;
|
||||
|
||||
return new_layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_anchor_rect:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @anchor_rect: the new anchor rectangle
|
||||
*
|
||||
* Set the anchor rectangle.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_anchor_rect (GdkPopupLayout *layout,
|
||||
const GdkRectangle *anchor_rect)
|
||||
{
|
||||
layout->anchor_rect = *anchor_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_anchor_rect:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Get the anchor rectangle.
|
||||
*
|
||||
* Returns: The anchor rectangle.
|
||||
*/
|
||||
const GdkRectangle *
|
||||
gdk_popup_layout_get_anchor_rect (GdkPopupLayout *layout)
|
||||
{
|
||||
return &layout->anchor_rect;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_rect_anchor:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @anchor: the new rect anchor
|
||||
*
|
||||
* Set the anchor on the anchor rectangle.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_rect_anchor (GdkPopupLayout *layout,
|
||||
GdkGravity anchor)
|
||||
{
|
||||
layout->rect_anchor = anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_rect_anchor:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Returns: the anchor on the anchor rectangle.
|
||||
*/
|
||||
GdkGravity
|
||||
gdk_popup_layout_get_rect_anchor (GdkPopupLayout *layout)
|
||||
{
|
||||
return layout->rect_anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_surface_anchor:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @anchor: the new popup surface anchor
|
||||
*
|
||||
* Set the anchor on the popup surface.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_surface_anchor (GdkPopupLayout *layout,
|
||||
GdkGravity anchor)
|
||||
{
|
||||
layout->surface_anchor = anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_surface_anchor:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Returns: the anchor on the popup surface.
|
||||
*/
|
||||
GdkGravity
|
||||
gdk_popup_layout_get_surface_anchor (GdkPopupLayout *layout)
|
||||
{
|
||||
return layout->surface_anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_anchor_hints:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @anchor_hints: the new #GdkAnchorHints
|
||||
*
|
||||
* Set new anchor hints.
|
||||
*
|
||||
* The set @anchor_hints determines how @surface will be moved if the anchor
|
||||
* points cause it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will
|
||||
* replace %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa
|
||||
* if @surface extends beyond the left or right edges of the monitor.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_anchor_hints (GdkPopupLayout *layout,
|
||||
GdkAnchorHints anchor_hints)
|
||||
{
|
||||
layout->anchor_hints = anchor_hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_anchor_hints:
|
||||
* @layout: a #GdkPopupLayout
|
||||
*
|
||||
* Get the #GdkAnchorHints.
|
||||
*
|
||||
* Returns: the #GdkAnchorHints.
|
||||
*/
|
||||
GdkAnchorHints
|
||||
gdk_popup_layout_get_anchor_hints (GdkPopupLayout *layout)
|
||||
{
|
||||
return layout->anchor_hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_set_offset:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @dx: x delta to offset the anchor rectangle with
|
||||
* @dy: y delta to offset the anchor rectangle with
|
||||
*
|
||||
* Offset the position of the anchor rectangle with the given delta.
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_set_offset (GdkPopupLayout *layout,
|
||||
int dx,
|
||||
int dy)
|
||||
{
|
||||
layout->dx = dx;
|
||||
layout->dy = dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_popup_layout_get_offset:
|
||||
* @layout: a #GdkPopupLayout
|
||||
* @dx: a pointer to where to store the delta x coordinate
|
||||
* @dy: a pointer to where to store the delta y coordinate
|
||||
*
|
||||
* Get the delta the anchor rectangle is offset with
|
||||
*/
|
||||
void
|
||||
gdk_popup_layout_get_offset (GdkPopupLayout *layout,
|
||||
int *dx,
|
||||
int *dy)
|
||||
{
|
||||
if (dx)
|
||||
*dx = layout->dx;
|
||||
if (dy)
|
||||
*dy = layout->dy;
|
||||
}
|
136
gdk/gdkpopuplayout.h
Normal file
136
gdk/gdkpopuplayout.h
Normal file
@ -0,0 +1,136 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2020 Red Hat
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GDK_POPUP_LAYOUT_H__
|
||||
#define __GDK_POPUP_LAYOUT_H__
|
||||
|
||||
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkversionmacros.h>
|
||||
#include <gdk/gdktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GdkAnchorHints:
|
||||
* @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
|
||||
* @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
|
||||
* @GDK_ANCHOR_SLIDE_X: allow sliding surface horizontally
|
||||
* @GDK_ANCHOR_SLIDE_Y: allow sliding surface vertically
|
||||
* @GDK_ANCHOR_RESIZE_X: allow resizing surface horizontally
|
||||
* @GDK_ANCHOR_RESIZE_Y: allow resizing surface vertically
|
||||
* @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
|
||||
* @GDK_ANCHOR_SLIDE: allow sliding surface on both axes
|
||||
* @GDK_ANCHOR_RESIZE: allow resizing surface on both axes
|
||||
*
|
||||
* Positioning hints for aligning a surface relative to a rectangle.
|
||||
*
|
||||
* These hints determine how the surface should be positioned in the case that
|
||||
* the surface would fall off-screen if placed in its ideal position.
|
||||
*
|
||||
* For example, %GDK_ANCHOR_FLIP_X will replace %GDK_GRAVITY_NORTH_WEST with
|
||||
* %GDK_GRAVITY_NORTH_EAST and vice versa if the surface extends beyond the left
|
||||
* or right edges of the monitor.
|
||||
*
|
||||
* If %GDK_ANCHOR_SLIDE_X is set, the surface can be shifted horizontally to fit
|
||||
* on-screen. If %GDK_ANCHOR_RESIZE_X is set, the surface can be shrunken
|
||||
* horizontally to fit.
|
||||
*
|
||||
* In general, when multiple flags are set, flipping should take precedence over
|
||||
* sliding, which should take precedence over resizing.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GDK_ANCHOR_FLIP_X = 1 << 0,
|
||||
GDK_ANCHOR_FLIP_Y = 1 << 1,
|
||||
GDK_ANCHOR_SLIDE_X = 1 << 2,
|
||||
GDK_ANCHOR_SLIDE_Y = 1 << 3,
|
||||
GDK_ANCHOR_RESIZE_X = 1 << 4,
|
||||
GDK_ANCHOR_RESIZE_Y = 1 << 5,
|
||||
GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y,
|
||||
GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y,
|
||||
GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y,
|
||||
} GdkAnchorHints;
|
||||
|
||||
/**
|
||||
* GdkPopupLayout:
|
||||
*/
|
||||
typedef struct _GdkPopupLayout GdkPopupLayout;
|
||||
|
||||
#define GDK_TYPE_POPUP_LAYOUT (gdk_popup_layout_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gdk_popup_layout_get_type (void);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkPopupLayout * gdk_popup_layout_new (const GdkRectangle *anchor_rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkPopupLayout * gdk_popup_layout_ref (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_unref (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkPopupLayout * gdk_popup_layout_copy (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_set_anchor_rect (GdkPopupLayout *layout,
|
||||
const GdkRectangle *anchor_rect);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const GdkRectangle * gdk_popup_layout_get_anchor_rect (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_set_rect_anchor (GdkPopupLayout *layout,
|
||||
GdkGravity anchor);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkGravity gdk_popup_layout_get_rect_anchor (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_set_surface_anchor (GdkPopupLayout *layout,
|
||||
GdkGravity anchor);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkGravity gdk_popup_layout_get_surface_anchor (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_set_anchor_hints (GdkPopupLayout *layout,
|
||||
GdkAnchorHints anchor_hints);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkAnchorHints gdk_popup_layout_get_anchor_hints (GdkPopupLayout *layout);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_set_offset (GdkPopupLayout *layout,
|
||||
int dx,
|
||||
int dy);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_popup_layout_get_offset (GdkPopupLayout *layout,
|
||||
int *dx,
|
||||
int *dy);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_POPUP_LAYOUT_H__ */
|
281
gdk/gdksurface.c
281
gdk/gdksurface.c
@ -69,7 +69,7 @@
|
||||
*/
|
||||
|
||||
enum {
|
||||
MOVED_TO_RECT,
|
||||
POPUP_LAYOUT_CHANGED,
|
||||
SIZE_CHANGED,
|
||||
RENDER,
|
||||
EVENT,
|
||||
@ -247,36 +247,30 @@ maybe_flip_position (gint bounds_pos,
|
||||
}
|
||||
|
||||
void
|
||||
gdk_surface_move_to_rect_helper (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy,
|
||||
GdkSurfaceMovedToRect moved_to_rect)
|
||||
gdk_surface_layout_popup_helper (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout,
|
||||
GdkRectangle *out_final_rect)
|
||||
{
|
||||
GdkSurface *toplevel;
|
||||
GdkDisplay *display;
|
||||
GdkMonitor *monitor;
|
||||
GdkRectangle bounds;
|
||||
GdkRectangle root_rect = *rect;
|
||||
GdkRectangle flipped_rect;
|
||||
GdkRectangle root_rect;
|
||||
GdkGravity rect_anchor;
|
||||
GdkGravity surface_anchor;
|
||||
int rect_anchor_dx;
|
||||
int rect_anchor_dy;
|
||||
GdkAnchorHints anchor_hints;
|
||||
GdkRectangle final_rect;
|
||||
gboolean flipped_x;
|
||||
gboolean flipped_y;
|
||||
int x, y;
|
||||
|
||||
/* This implementation only works for backends that
|
||||
* can provide root coordinates via get_root_coords.
|
||||
* Other backends need to implement move_to_rect.
|
||||
*/
|
||||
if (surface->surface_type == GDK_SURFACE_POPUP)
|
||||
toplevel = surface->parent;
|
||||
else
|
||||
toplevel = surface->transient_for;
|
||||
g_return_if_fail (surface->surface_type == GDK_SURFACE_POPUP);
|
||||
|
||||
gdk_surface_get_root_coords (toplevel,
|
||||
root_rect = *gdk_popup_layout_get_anchor_rect (layout);
|
||||
gdk_surface_get_root_coords (surface->parent,
|
||||
root_rect.x,
|
||||
root_rect.y,
|
||||
&root_rect.x,
|
||||
@ -286,30 +280,33 @@ gdk_surface_move_to_rect_helper (GdkSurface *surface,
|
||||
monitor = get_monitor_for_rect (display, &root_rect);
|
||||
gdk_monitor_get_workarea (monitor, &bounds);
|
||||
|
||||
flipped_rect.width = surface->width - surface->shadow_left - surface->shadow_right;
|
||||
flipped_rect.height = surface->height - surface->shadow_top - surface->shadow_bottom;
|
||||
flipped_rect.x = maybe_flip_position (bounds.x,
|
||||
bounds.width,
|
||||
root_rect.x,
|
||||
root_rect.width,
|
||||
flipped_rect.width,
|
||||
get_anchor_x_sign (rect_anchor),
|
||||
get_anchor_x_sign (surface_anchor),
|
||||
rect_anchor_dx,
|
||||
anchor_hints & GDK_ANCHOR_FLIP_X,
|
||||
&flipped_x);
|
||||
flipped_rect.y = maybe_flip_position (bounds.y,
|
||||
bounds.height,
|
||||
root_rect.y,
|
||||
root_rect.height,
|
||||
flipped_rect.height,
|
||||
get_anchor_y_sign (rect_anchor),
|
||||
get_anchor_y_sign (surface_anchor),
|
||||
rect_anchor_dy,
|
||||
anchor_hints & GDK_ANCHOR_FLIP_Y,
|
||||
&flipped_y);
|
||||
rect_anchor = gdk_popup_layout_get_rect_anchor (layout);
|
||||
surface_anchor = gdk_popup_layout_get_surface_anchor (layout);
|
||||
gdk_popup_layout_get_offset (layout, &rect_anchor_dx, &rect_anchor_dy);
|
||||
anchor_hints = gdk_popup_layout_get_anchor_hints (layout);
|
||||
|
||||
final_rect = flipped_rect;
|
||||
final_rect.width = width - surface->shadow_left - surface->shadow_right;
|
||||
final_rect.height = height - surface->shadow_top - surface->shadow_bottom;
|
||||
final_rect.x = maybe_flip_position (bounds.x,
|
||||
bounds.width,
|
||||
root_rect.x,
|
||||
root_rect.width,
|
||||
final_rect.width,
|
||||
get_anchor_x_sign (rect_anchor),
|
||||
get_anchor_x_sign (surface_anchor),
|
||||
rect_anchor_dx,
|
||||
anchor_hints & GDK_ANCHOR_FLIP_X,
|
||||
&flipped_x);
|
||||
final_rect.y = maybe_flip_position (bounds.y,
|
||||
bounds.height,
|
||||
root_rect.y,
|
||||
root_rect.height,
|
||||
final_rect.height,
|
||||
get_anchor_y_sign (rect_anchor),
|
||||
get_anchor_y_sign (surface_anchor),
|
||||
rect_anchor_dy,
|
||||
anchor_hints & GDK_ANCHOR_FLIP_Y,
|
||||
&flipped_y);
|
||||
|
||||
if (anchor_hints & GDK_ANCHOR_SLIDE_X)
|
||||
{
|
||||
@ -353,30 +350,30 @@ gdk_surface_move_to_rect_helper (GdkSurface *surface,
|
||||
final_rect.height = bounds.y + bounds.height - final_rect.y;
|
||||
}
|
||||
|
||||
flipped_rect.x -= surface->shadow_left;
|
||||
flipped_rect.y -= surface->shadow_top;
|
||||
flipped_rect.width += surface->shadow_left + surface->shadow_right;
|
||||
flipped_rect.height += surface->shadow_top + surface->shadow_bottom;
|
||||
|
||||
final_rect.x -= surface->shadow_left;
|
||||
final_rect.y -= surface->shadow_top;
|
||||
final_rect.width += surface->shadow_left + surface->shadow_right;
|
||||
final_rect.height += surface->shadow_top + surface->shadow_bottom;
|
||||
|
||||
gdk_surface_get_origin (toplevel, &x, &y);
|
||||
gdk_surface_get_origin (surface->parent, &x, &y);
|
||||
final_rect.x -= x;
|
||||
final_rect.y -= y;
|
||||
flipped_rect.x -= x;
|
||||
flipped_rect.y -= y;
|
||||
|
||||
moved_to_rect (surface, final_rect);
|
||||
if (flipped_x)
|
||||
{
|
||||
rect_anchor = gdk_gravity_flip_horizontally (rect_anchor);
|
||||
surface_anchor = gdk_gravity_flip_horizontally (surface_anchor);
|
||||
}
|
||||
if (flipped_y)
|
||||
{
|
||||
rect_anchor = gdk_gravity_flip_vertically (rect_anchor);
|
||||
surface_anchor = gdk_gravity_flip_vertically (surface_anchor);
|
||||
}
|
||||
|
||||
g_signal_emit_by_name (surface,
|
||||
"moved-to-rect",
|
||||
&flipped_rect,
|
||||
&final_rect,
|
||||
flipped_x,
|
||||
flipped_y);
|
||||
surface->popup.rect_anchor = rect_anchor;
|
||||
surface->popup.surface_anchor = surface_anchor;
|
||||
|
||||
*out_final_rect = final_rect;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -481,42 +478,24 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
|
||||
g_object_class_install_properties (object_class, LAST_PROP, properties);
|
||||
|
||||
/**
|
||||
* GdkSurface::moved-to-rect:
|
||||
* @surface: the #GdkSurface that moved
|
||||
* @flipped_rect: (nullable): the position of @surface after any possible
|
||||
* flipping or %NULL if the backend can't obtain it
|
||||
* @final_rect: (nullable): the final position of @surface or %NULL if the
|
||||
* backend can't obtain it
|
||||
* @flipped_x: %TRUE if the anchors were flipped horizontally
|
||||
* @flipped_y: %TRUE if the anchors were flipped vertically
|
||||
* GdkSurface::popup-layout-changed
|
||||
* @surface: the #GdkSurface that was laid out
|
||||
*
|
||||
* Emitted when the position of @surface is finalized after being moved to a
|
||||
* destination rectangle.
|
||||
* Emitted when the layout of a popup @surface has changed, e.g. if the popup
|
||||
* layout was reactive and after the parent moved causing the popover to end
|
||||
* up partially off-screen.
|
||||
*
|
||||
* @surface might be flipped over the destination rectangle in order to keep
|
||||
* it on-screen, in which case @flipped_x and @flipped_y will be set to %TRUE
|
||||
* accordingly.
|
||||
*
|
||||
* @flipped_rect is the ideal position of @surface after any possible
|
||||
* flipping, but before any possible sliding. @final_rect is @flipped_rect,
|
||||
* but possibly translated in the case that flipping is still ineffective in
|
||||
* keeping @surface on-screen.
|
||||
* Stability: Private
|
||||
*/
|
||||
signals[MOVED_TO_RECT] =
|
||||
g_signal_new (g_intern_static_string ("moved-to-rect"),
|
||||
signals[POPUP_LAYOUT_CHANGED] =
|
||||
g_signal_new (g_intern_static_string ("popup-layout-changed"),
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
_gdk_marshal_VOID__POINTER_POINTER_BOOLEAN_BOOLEAN,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
4,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_BOOLEAN);
|
||||
0);
|
||||
|
||||
/**
|
||||
* GdkSurface::size-changed:
|
||||
@ -805,9 +784,8 @@ gdk_surface_new_temp (GdkDisplay *display,
|
||||
*
|
||||
* Create a new popup surface.
|
||||
*
|
||||
* The surface will be attached to @parent and can
|
||||
* be positioned relative to it using
|
||||
* gdk_surface_move_to_rect().
|
||||
* The surface will be attached to @parent and can be positioned relative to it
|
||||
* using gdk_surface_show_popup() or later using gdk_surface_layout_popup().
|
||||
*
|
||||
* Returns: (transfer full): a new #GdkSurface
|
||||
*/
|
||||
@ -1985,14 +1963,6 @@ gdk_surface_restack (GdkSurface *surface,
|
||||
GDK_SURFACE_GET_CLASS (surface)->restack_toplevel (surface, sibling, above);
|
||||
}
|
||||
|
||||
static void
|
||||
grab_prepare_func (GdkSeat *seat,
|
||||
GdkSurface *surface,
|
||||
gpointer data)
|
||||
{
|
||||
gdk_surface_show_internal (surface, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_surface_show:
|
||||
* @surface: a #GdkSurface
|
||||
@ -2004,25 +1974,18 @@ grab_prepare_func (GdkSeat *seat,
|
||||
* This function maps a surface so it’s visible onscreen. Its opposite
|
||||
* is gdk_surface_hide().
|
||||
*
|
||||
* This function may not be used on a #GdkSurface with the surface type
|
||||
* GTK_SURFACE_POPUP.
|
||||
*
|
||||
* When implementing a #GtkWidget, you should call this function on the widget's
|
||||
* #GdkSurface as part of the “map” method.
|
||||
*/
|
||||
void
|
||||
gdk_surface_show (GdkSurface *surface)
|
||||
{
|
||||
if (surface->autohide)
|
||||
{
|
||||
gdk_seat_grab (gdk_display_get_default_seat (surface->display),
|
||||
surface,
|
||||
GDK_SEAT_CAPABILITY_ALL,
|
||||
TRUE,
|
||||
NULL, NULL,
|
||||
grab_prepare_func, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
gdk_surface_show_internal (surface, TRUE);
|
||||
}
|
||||
g_return_if_fail (surface->surface_type != GDK_SURFACE_POPUP);
|
||||
|
||||
gdk_surface_show_internal (surface, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2084,6 +2047,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
GDK_SURFACE_GET_CLASS (surface)->hide (surface);
|
||||
|
||||
surface->popup.rect_anchor = 0;
|
||||
surface->popup.surface_anchor = 0;
|
||||
surface->x = 0;
|
||||
surface->y = 0;
|
||||
}
|
||||
@ -2109,52 +2074,70 @@ gdk_surface_resize (GdkSurface *surface,
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_surface_move_to_rect:
|
||||
* @surface: the #GdkSurface to move
|
||||
* @rect: (not nullable): the destination #GdkRectangle to align @surface with
|
||||
* @rect_anchor: the point on @rect to align with @surface's anchor point
|
||||
* @surface_anchor: the point on @surface to align with @rect's anchor point
|
||||
* @anchor_hints: positioning hints to use when limited on space
|
||||
* @rect_anchor_dx: horizontal offset to shift @surface, i.e. @rect's anchor
|
||||
* point
|
||||
* @rect_anchor_dy: vertical offset to shift @surface, i.e. @rect's anchor point
|
||||
* gdk_surface_present_popup:
|
||||
* @surface: the popup #GdkSurface to show
|
||||
* @width: the unconstrained popup width to layout
|
||||
* @height: the unconstrained popup height to layout
|
||||
* @layout: the #GdkPopupLayout object used to layout
|
||||
*
|
||||
* Moves @surface to @rect, aligning their anchor points.
|
||||
* Present @surface after having processed the #GdkPopupLayout rules. If the
|
||||
* popup was previously now showing, it will be showed, otherwise it will
|
||||
* change position according to @layout.
|
||||
*
|
||||
* @rect is relative to the top-left corner of the surface that @surface is
|
||||
* transient for. @rect_anchor and @surface_anchor determine anchor points on
|
||||
* @rect and @surface to pin together. @rect's anchor point can optionally be
|
||||
* offset by @rect_anchor_dx and @rect_anchor_dy, which is equivalent to
|
||||
* offsetting the position of @surface.
|
||||
* After calling this function, the result of the layout can be queried
|
||||
* using gdk_surface_get_position(), gdk_surface_get_width(),
|
||||
* gdk_surface_get_height(), gdk_surface_get_popup_rect_anchor() and
|
||||
* gdk_surface_get_popup_surface_anchor().
|
||||
*
|
||||
* @anchor_hints determines how @surface will be moved if the anchor points cause
|
||||
* it to move off-screen. For example, %GDK_ANCHOR_FLIP_X will replace
|
||||
* %GDK_GRAVITY_NORTH_WEST with %GDK_GRAVITY_NORTH_EAST and vice versa if
|
||||
* @surface extends beyond the left or right edges of the monitor.
|
||||
* Presenting may have fail, for example if it was immediately hidden if the
|
||||
* @surface was set to autohide.
|
||||
*
|
||||
* Connect to the #GdkSurface::moved-to-rect signal to find out how it was
|
||||
* actually positioned.
|
||||
* Returns: %FALSE if it failed to be presented, otherwise %TRUE.
|
||||
*/
|
||||
void
|
||||
gdk_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
gboolean
|
||||
gdk_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_SURFACE (surface));
|
||||
g_return_if_fail (surface->parent || surface->transient_for);
|
||||
g_return_if_fail (rect);
|
||||
g_return_val_if_fail (GDK_IS_SURFACE (surface), FALSE);
|
||||
g_return_val_if_fail (surface->parent, FALSE);
|
||||
g_return_val_if_fail (layout, FALSE);
|
||||
g_return_val_if_fail (!GDK_SURFACE_DESTROYED (surface), FALSE);
|
||||
g_return_val_if_fail (width > 0 && height > 0, FALSE);
|
||||
|
||||
GDK_SURFACE_GET_CLASS (surface)->move_to_rect (surface,
|
||||
rect,
|
||||
rect_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy);
|
||||
return GDK_SURFACE_GET_CLASS (surface)->present_popup (surface,
|
||||
width,
|
||||
height,
|
||||
layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_surface_get_popup_surface_anchor:
|
||||
* @surface: a #GdkSurface
|
||||
*
|
||||
* Get the current popup surface anchor. The value returned may chage after
|
||||
* calling gdk_surface_show_popup(), gdk_surface_layout_popup() or after the
|
||||
* "popup-layout-changed" is emitted.
|
||||
*/
|
||||
GdkGravity
|
||||
gdk_surface_get_popup_surface_anchor (GdkSurface *surface)
|
||||
{
|
||||
return surface->popup.surface_anchor;
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_surface_get_popup_rect_anchor:
|
||||
* @surface: a #GdkSurface
|
||||
*
|
||||
* Get the current popup anchor rectangle anchor. The value
|
||||
* returned may chage after calling gdk_surface_show_popup(),
|
||||
* gdk_surface_layout_popup() or after the "popup-layout-changed" is emitted.
|
||||
*/
|
||||
GdkGravity
|
||||
gdk_surface_get_popup_rect_anchor (GdkSurface *surface)
|
||||
{
|
||||
return surface->popup.rect_anchor;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <gdk/gdkevents.h>
|
||||
#include <gdk/gdkframeclock.h>
|
||||
#include <gdk/gdkmonitor.h>
|
||||
#include <gdk/gdkpopuplayout.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -143,47 +144,6 @@ typedef enum
|
||||
GDK_FUNC_CLOSE = 1 << 5
|
||||
} GdkWMFunction;
|
||||
|
||||
/**
|
||||
* GdkAnchorHints:
|
||||
* @GDK_ANCHOR_FLIP_X: allow flipping anchors horizontally
|
||||
* @GDK_ANCHOR_FLIP_Y: allow flipping anchors vertically
|
||||
* @GDK_ANCHOR_SLIDE_X: allow sliding surface horizontally
|
||||
* @GDK_ANCHOR_SLIDE_Y: allow sliding surface vertically
|
||||
* @GDK_ANCHOR_RESIZE_X: allow resizing surface horizontally
|
||||
* @GDK_ANCHOR_RESIZE_Y: allow resizing surface vertically
|
||||
* @GDK_ANCHOR_FLIP: allow flipping anchors on both axes
|
||||
* @GDK_ANCHOR_SLIDE: allow sliding surface on both axes
|
||||
* @GDK_ANCHOR_RESIZE: allow resizing surface on both axes
|
||||
*
|
||||
* Positioning hints for aligning a surface relative to a rectangle.
|
||||
*
|
||||
* These hints determine how the surface should be positioned in the case that
|
||||
* the surface would fall off-screen if placed in its ideal position.
|
||||
*
|
||||
* For example, %GDK_ANCHOR_FLIP_X will replace %GDK_GRAVITY_NORTH_WEST with
|
||||
* %GDK_GRAVITY_NORTH_EAST and vice versa if the surface extends beyond the left
|
||||
* or right edges of the monitor.
|
||||
*
|
||||
* If %GDK_ANCHOR_SLIDE_X is set, the surface can be shifted horizontally to fit
|
||||
* on-screen. If %GDK_ANCHOR_RESIZE_X is set, the surface can be shrunken
|
||||
* horizontally to fit.
|
||||
*
|
||||
* In general, when multiple flags are set, flipping should take precedence over
|
||||
* sliding, which should take precedence over resizing.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GDK_ANCHOR_FLIP_X = 1 << 0,
|
||||
GDK_ANCHOR_FLIP_Y = 1 << 1,
|
||||
GDK_ANCHOR_SLIDE_X = 1 << 2,
|
||||
GDK_ANCHOR_SLIDE_Y = 1 << 3,
|
||||
GDK_ANCHOR_RESIZE_X = 1 << 4,
|
||||
GDK_ANCHOR_RESIZE_Y = 1 << 5,
|
||||
GDK_ANCHOR_FLIP = GDK_ANCHOR_FLIP_X | GDK_ANCHOR_FLIP_Y,
|
||||
GDK_ANCHOR_SLIDE = GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_SLIDE_Y,
|
||||
GDK_ANCHOR_RESIZE = GDK_ANCHOR_RESIZE_X | GDK_ANCHOR_RESIZE_Y
|
||||
} GdkAnchorHints;
|
||||
|
||||
/**
|
||||
* GdkSurfaceEdge:
|
||||
* @GDK_SURFACE_EDGE_NORTH_WEST: the top left corner.
|
||||
@ -407,13 +367,14 @@ void gdk_surface_resize (GdkSurface *surface,
|
||||
gint width,
|
||||
gint height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy);
|
||||
gboolean gdk_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkGravity gdk_surface_get_popup_surface_anchor (GdkSurface *surface);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkGravity gdk_surface_get_popup_rect_anchor (GdkSurface *surface);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_surface_raise (GdkSurface *surface);
|
||||
|
@ -73,6 +73,11 @@ struct _GdkSurface
|
||||
guint frame_clock_events_paused : 1;
|
||||
guint autohide : 1;
|
||||
|
||||
struct {
|
||||
GdkGravity surface_anchor;
|
||||
GdkGravity rect_anchor;
|
||||
} popup;
|
||||
|
||||
guint update_and_descendants_freeze_count;
|
||||
|
||||
gint width, height;
|
||||
@ -116,13 +121,10 @@ struct _GdkSurfaceClass
|
||||
void (* toplevel_resize) (GdkSurface *surface,
|
||||
gint width,
|
||||
gint height);
|
||||
void (* move_to_rect) (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy);
|
||||
gboolean (* present_popup) (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout);
|
||||
|
||||
void (* get_geometry) (GdkSurface *surface,
|
||||
gint *x,
|
||||
@ -255,18 +257,71 @@ struct _GdkSurfaceClass
|
||||
void gdk_surface_set_state (GdkSurface *surface,
|
||||
GdkSurfaceState new_state);
|
||||
|
||||
typedef void (* GdkSurfaceMovedToRect) (GdkSurface *surface,
|
||||
GdkRectangle final_rect);
|
||||
void gdk_surface_layout_popup_helper (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout,
|
||||
GdkRectangle *out_final_rect);
|
||||
|
||||
void
|
||||
gdk_surface_move_to_rect_helper (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy,
|
||||
GdkSurfaceMovedToRect moved_to_rect);
|
||||
static inline GdkGravity
|
||||
gdk_gravity_flip_horizontally (GdkGravity anchor)
|
||||
{
|
||||
switch (anchor)
|
||||
{
|
||||
default:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
return GDK_GRAVITY_NORTH_EAST;
|
||||
case GDK_GRAVITY_NORTH:
|
||||
return GDK_GRAVITY_NORTH;
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
return GDK_GRAVITY_NORTH_WEST;
|
||||
case GDK_GRAVITY_WEST:
|
||||
return GDK_GRAVITY_EAST;
|
||||
case GDK_GRAVITY_CENTER:
|
||||
return GDK_GRAVITY_CENTER;
|
||||
case GDK_GRAVITY_EAST:
|
||||
return GDK_GRAVITY_WEST;
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
return GDK_GRAVITY_SOUTH_EAST;
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return GDK_GRAVITY_SOUTH;
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
return GDK_GRAVITY_SOUTH_WEST;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static inline GdkGravity
|
||||
gdk_gravity_flip_vertically (GdkGravity anchor)
|
||||
{
|
||||
switch (anchor)
|
||||
{
|
||||
default:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
return GDK_GRAVITY_SOUTH_WEST;
|
||||
case GDK_GRAVITY_NORTH:
|
||||
return GDK_GRAVITY_SOUTH;
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
return GDK_GRAVITY_SOUTH_EAST;
|
||||
case GDK_GRAVITY_WEST:
|
||||
return GDK_GRAVITY_WEST;
|
||||
case GDK_GRAVITY_CENTER:
|
||||
return GDK_GRAVITY_CENTER;
|
||||
case GDK_GRAVITY_EAST:
|
||||
return GDK_GRAVITY_EAST;
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
return GDK_GRAVITY_NORTH_WEST;
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return GDK_GRAVITY_NORTH;
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
return GDK_GRAVITY_NORTH_EAST;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -45,6 +45,7 @@ gdk_public_sources = files([
|
||||
'gdktexture.c',
|
||||
'gdkvulkancontext.c',
|
||||
'gdksurface.c',
|
||||
'gdkpopuplayout.c',
|
||||
'gdkprofiler.c'
|
||||
])
|
||||
|
||||
@ -90,6 +91,7 @@ gdk_public_headers = files([
|
||||
'gdktypes.h',
|
||||
'gdkvulkancontext.h',
|
||||
'gdksurface.h',
|
||||
'gdkpopuplayout.h',
|
||||
])
|
||||
install_headers(gdk_public_headers, subdir: 'gtk-4.0/gdk/')
|
||||
|
||||
|
@ -1245,51 +1245,83 @@ gdk_surface_quartz_toplevel_resize (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_quartz_surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle final_rect)
|
||||
gdk_quartz_surface_layout_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
GdkSurface *toplevel;
|
||||
GdkRectangle final_rect;
|
||||
int x, y;
|
||||
|
||||
if (surface->surface_type == GDK_SURFACE_POPUP)
|
||||
toplevel = surface->parent;
|
||||
else
|
||||
toplevel = surface->transient_for;
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
layout,
|
||||
&final_rect);
|
||||
|
||||
gdk_surface_get_origin (toplevel, &x, &y);
|
||||
gdk_surface_get_origin (surface->parent, &x, &y);
|
||||
x += final_rect.x;
|
||||
y += final_rect.y;
|
||||
|
||||
if (final_rect.width != surface->width ||
|
||||
final_rect.height != surface->height)
|
||||
{
|
||||
window_quartz_move_resize (surface,
|
||||
x, y,
|
||||
final_rect.width, final_rect.height);
|
||||
move_resize_window_internal (surface,
|
||||
x,
|
||||
y,
|
||||
final_rect.width,
|
||||
final_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
window_quartz_resize (surface, final_rect.width, final_rect.height);
|
||||
window_quartz_move (surface, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_quartz_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
show_popup (GdkSurface *surface)
|
||||
{
|
||||
gdk_surface_move_to_rect_helper (surface,
|
||||
rect,
|
||||
rect_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy,
|
||||
gdk_quartz_surface_moved_to_rect);
|
||||
gdk_surface_raise (surface);
|
||||
gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
|
||||
_gdk_surface_update_viewable (surface);
|
||||
gdk_quartz_surface_show (surface, FALSE);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
show_grabbing_popup (GdkSeat *seat,
|
||||
GdkSurface *surface,
|
||||
gpointer user_data)
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_quartz_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
gdk_quartz_surface_layout_popup (surface, width, height, layout);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
return TRUE;
|
||||
|
||||
if (surface->autohide)
|
||||
{
|
||||
gdk_seat_grab (gdk_display_get_default_seat (surface->display),
|
||||
surface,
|
||||
GDK_SEAT_CAPABILITY_ALL,
|
||||
TRUE,
|
||||
NULL, NULL,
|
||||
show_grabbing_popup, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
return GDK_SURFACE_IS_MAPPED (surface);
|
||||
}
|
||||
|
||||
/* Get the toplevel ordering from NSApp and update our own list. We do
|
||||
@ -2675,7 +2707,7 @@ gdk_surface_impl_quartz_class_init (GdkSurfaceImplQuartzClass *klass)
|
||||
impl_class->lower = gdk_surface_quartz_lower;
|
||||
impl_class->restack_toplevel = gdk_surface_quartz_restack_toplevel;
|
||||
impl_class->toplevel_resize = gdk_surface_quartz_toplevel_resize;
|
||||
impl_class->move_to_rect = gdk_surface_quartz_move_to_rect;
|
||||
impl_class->present_popup = gdk_quartz_surface_present_popup;
|
||||
impl_class->get_geometry = gdk_surface_quartz_get_geometry;
|
||||
impl_class->get_root_coords = gdk_surface_quartz_get_root_coords;
|
||||
impl_class->get_device_state = gdk_surface_quartz_get_device_state;
|
||||
|
@ -4593,8 +4593,6 @@ gdk_wayland_seat_grab (GdkSeat *seat,
|
||||
if (!gdk_surface_is_visible (surface))
|
||||
{
|
||||
gdk_wayland_seat_set_grab_surface (wayland_seat, NULL);
|
||||
g_critical ("Surface %p has not been made visible in GdkSeatGrabPrepareFunc",
|
||||
surface);
|
||||
return GDK_GRAB_NOT_VIEWABLE;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1289,18 +1289,21 @@ gdk_win32_surface_move (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle final_rect)
|
||||
gdk_win32_surface_layout_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
GdkSurface *toplevel;
|
||||
GdkRectangle final_rect;
|
||||
int x, y;
|
||||
|
||||
if (surface->surface_type == GDK_SURFACE_POPUP)
|
||||
toplevel = surface->parent;
|
||||
else
|
||||
toplevel = surface->transient_for;
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
layout,
|
||||
&final_rect);
|
||||
|
||||
gdk_surface_get_origin (toplevel, &x, &y);
|
||||
gdk_surface_get_origin (surface->parent, &x, &y);
|
||||
x += final_rect.x;
|
||||
y += final_rect.y;
|
||||
|
||||
@ -1308,8 +1311,10 @@ gdk_win32_surface_moved_to_rect (GdkSurface *surface,
|
||||
final_rect.height != surface->height)
|
||||
{
|
||||
gdk_win32_surface_move_resize (surface,
|
||||
x, y,
|
||||
final_rect.width, final_rect.height);
|
||||
x,
|
||||
y,
|
||||
final_rect.width,
|
||||
final_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1318,22 +1323,49 @@ gdk_win32_surface_moved_to_rect (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
show_popup (GdkSurface *surface)
|
||||
{
|
||||
gdk_surface_move_to_rect_helper (surface,
|
||||
rect,
|
||||
rect_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy,
|
||||
gdk_win32_surface_moved_to_rect);
|
||||
gdk_surface_raise (surface);
|
||||
gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
|
||||
_gdk_surface_update_viewable (surface);
|
||||
show_window_internal (surface, FALSE, FALSE);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
show_grabbing_popup (GdkSeat *seat,
|
||||
GdkSurface *surface,
|
||||
gpointer user_data)
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_win32_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
gdk_win32_surface_layout_popup (surface, width, height, layout);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
return TRUE;
|
||||
|
||||
if (surface->autohide)
|
||||
{
|
||||
gdk_seat_grab (gdk_display_get_default_seat (surface->display),
|
||||
surface,
|
||||
GDK_SEAT_CAPABILITY_ALL,
|
||||
TRUE,
|
||||
NULL, NULL,
|
||||
show_grabbing_popup, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
return GDK_SURFACE_IS_MAPPED (surface);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5161,7 +5193,7 @@ gdk_win32_surface_class_init (GdkWin32SurfaceClass *klass)
|
||||
impl_class->lower = gdk_win32_surface_lower;
|
||||
impl_class->restack_toplevel = gdk_win32_surface_restack_toplevel;
|
||||
impl_class->toplevel_resize = gdk_win32_surface_toplevel_resize;
|
||||
impl_class->move_to_rect = gdk_win32_surface_move_to_rect;
|
||||
impl_class->present_popup = gdk_win32_surface_present_popup;
|
||||
impl_class->get_geometry = gdk_win32_surface_get_geometry;
|
||||
impl_class->get_device_state = gdk_surface_win32_get_device_state;
|
||||
impl_class->get_root_coords = gdk_win32_surface_get_root_coords;
|
||||
|
@ -1416,18 +1416,21 @@ gdk_x11_surface_move (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle final_rect)
|
||||
gdk_x11_surface_layout_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
GdkSurface *toplevel;
|
||||
GdkRectangle final_rect;
|
||||
int x, y;
|
||||
|
||||
if (surface->surface_type == GDK_SURFACE_POPUP)
|
||||
toplevel = surface->parent;
|
||||
else
|
||||
toplevel = surface->transient_for;
|
||||
gdk_surface_layout_popup_helper (surface,
|
||||
width,
|
||||
height,
|
||||
layout,
|
||||
&final_rect);
|
||||
|
||||
gdk_surface_get_origin (toplevel, &x, &y);
|
||||
gdk_surface_get_origin (surface->parent, &x, &y);
|
||||
x += final_rect.x;
|
||||
y += final_rect.y;
|
||||
|
||||
@ -1436,8 +1439,10 @@ gdk_x11_surface_moved_to_rect (GdkSurface *surface,
|
||||
{
|
||||
gdk_x11_surface_move_resize (surface,
|
||||
TRUE,
|
||||
x, y,
|
||||
final_rect.width, final_rect.height);
|
||||
x,
|
||||
y,
|
||||
final_rect.width,
|
||||
final_rect.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1446,22 +1451,49 @@ gdk_x11_surface_moved_to_rect (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_x11_surface_move_to_rect (GdkSurface *surface,
|
||||
const GdkRectangle *rect,
|
||||
GdkGravity rect_anchor,
|
||||
GdkGravity surface_anchor,
|
||||
GdkAnchorHints anchor_hints,
|
||||
gint rect_anchor_dx,
|
||||
gint rect_anchor_dy)
|
||||
show_popup (GdkSurface *surface)
|
||||
{
|
||||
gdk_surface_move_to_rect_helper (surface,
|
||||
rect,
|
||||
rect_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
rect_anchor_dx,
|
||||
rect_anchor_dy,
|
||||
gdk_x11_surface_moved_to_rect);
|
||||
gdk_surface_raise (surface);
|
||||
gdk_synthesize_surface_state (surface, GDK_SURFACE_STATE_WITHDRAWN, 0);
|
||||
_gdk_surface_update_viewable (surface);
|
||||
gdk_x11_surface_show (surface, FALSE);
|
||||
gdk_surface_invalidate_rect (surface, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
show_grabbing_popup (GdkSeat *seat,
|
||||
GdkSurface *surface,
|
||||
gpointer user_data)
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_x11_surface_present_popup (GdkSurface *surface,
|
||||
int width,
|
||||
int height,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
gdk_x11_surface_layout_popup (surface, width, height, layout);
|
||||
|
||||
if (GDK_SURFACE_IS_MAPPED (surface))
|
||||
return TRUE;
|
||||
|
||||
if (surface->autohide)
|
||||
{
|
||||
gdk_seat_grab (gdk_display_get_default_seat (surface->display),
|
||||
surface,
|
||||
GDK_SEAT_CAPABILITY_ALL,
|
||||
TRUE,
|
||||
NULL, NULL,
|
||||
show_grabbing_popup, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_popup (surface);
|
||||
}
|
||||
|
||||
return GDK_SURFACE_IS_MAPPED (surface);
|
||||
}
|
||||
|
||||
static void gdk_x11_surface_restack_toplevel (GdkSurface *surface,
|
||||
@ -4659,7 +4691,7 @@ gdk_x11_surface_class_init (GdkX11SurfaceClass *klass)
|
||||
impl_class->lower = gdk_x11_surface_lower;
|
||||
impl_class->restack_toplevel = gdk_x11_surface_restack_toplevel;
|
||||
impl_class->toplevel_resize = gdk_x11_surface_toplevel_resize;
|
||||
impl_class->move_to_rect = gdk_x11_surface_move_to_rect;
|
||||
impl_class->present_popup = gdk_x11_surface_present_popup;
|
||||
impl_class->get_geometry = gdk_x11_surface_get_geometry;
|
||||
impl_class->get_root_coords = gdk_x11_surface_get_root_coords;
|
||||
impl_class->get_device_state = gdk_x11_surface_get_device_state;
|
||||
|
299
gtk/gtkpopover.c
299
gtk/gtkpopover.c
@ -155,6 +155,7 @@ typedef struct {
|
||||
GtkCssNode *arrow_node;
|
||||
GskRenderNode *arrow_render_node;
|
||||
|
||||
GdkPopupLayout *layout;
|
||||
GdkRectangle final_rect;
|
||||
GtkPositionType final_position;
|
||||
} GtkPopoverPrivate;
|
||||
@ -221,14 +222,200 @@ gtk_popover_native_get_surface_transform (GtkNative *native,
|
||||
_gtk_css_number_value_get (style->size->padding_top, 100);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gravity_facing_north (GdkGravity gravity)
|
||||
{
|
||||
switch (gravity)
|
||||
{
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
case GDK_GRAVITY_NORTH:
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
return TRUE;
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
case GDK_GRAVITY_WEST:
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
case GDK_GRAVITY_EAST:
|
||||
case GDK_GRAVITY_CENTER:
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gravity_facing_south (GdkGravity gravity)
|
||||
{
|
||||
switch (gravity)
|
||||
{
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return TRUE;
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
case GDK_GRAVITY_NORTH:
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
case GDK_GRAVITY_WEST:
|
||||
case GDK_GRAVITY_EAST:
|
||||
case GDK_GRAVITY_CENTER:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gravity_facing_west (GdkGravity gravity)
|
||||
{
|
||||
switch (gravity)
|
||||
{
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
case GDK_GRAVITY_WEST:
|
||||
return TRUE;
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
case GDK_GRAVITY_EAST:
|
||||
case GDK_GRAVITY_NORTH:
|
||||
case GDK_GRAVITY_CENTER:
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_gravity_facing_east (GdkGravity gravity)
|
||||
{
|
||||
switch (gravity)
|
||||
{
|
||||
case GDK_GRAVITY_NORTH_EAST:
|
||||
case GDK_GRAVITY_SOUTH_EAST:
|
||||
case GDK_GRAVITY_EAST:
|
||||
return TRUE;
|
||||
case GDK_GRAVITY_NORTH_WEST:
|
||||
case GDK_GRAVITY_STATIC:
|
||||
case GDK_GRAVITY_SOUTH_WEST:
|
||||
case GDK_GRAVITY_WEST:
|
||||
case GDK_GRAVITY_NORTH:
|
||||
case GDK_GRAVITY_CENTER:
|
||||
case GDK_GRAVITY_SOUTH:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
did_flip_horizontally (GdkGravity original_gravity,
|
||||
GdkGravity final_gravity)
|
||||
{
|
||||
g_return_val_if_fail (original_gravity, FALSE);
|
||||
g_return_val_if_fail (final_gravity, FALSE);
|
||||
|
||||
if (is_gravity_facing_east (original_gravity) &&
|
||||
is_gravity_facing_west (final_gravity))
|
||||
return TRUE;
|
||||
|
||||
if (is_gravity_facing_west (original_gravity) &&
|
||||
is_gravity_facing_east (final_gravity))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
did_flip_vertically (GdkGravity original_gravity,
|
||||
GdkGravity final_gravity)
|
||||
{
|
||||
g_return_val_if_fail (original_gravity, FALSE);
|
||||
g_return_val_if_fail (final_gravity, FALSE);
|
||||
|
||||
if (is_gravity_facing_north (original_gravity) &&
|
||||
is_gravity_facing_south (final_gravity))
|
||||
return TRUE;
|
||||
|
||||
if (is_gravity_facing_south (original_gravity) &&
|
||||
is_gravity_facing_north (final_gravity))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
move_to_rect (GtkPopover *popover)
|
||||
update_popover_layout (GtkPopover *popover,
|
||||
GdkPopupLayout *layout)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GdkRectangle final_rect;
|
||||
gboolean flipped_x;
|
||||
gboolean flipped_y;
|
||||
|
||||
g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
|
||||
priv->layout = layout;
|
||||
|
||||
final_rect = (GdkRectangle) {
|
||||
.width = gdk_surface_get_width (priv->surface),
|
||||
.height = gdk_surface_get_height (priv->surface),
|
||||
};
|
||||
gdk_surface_get_position (priv->surface,
|
||||
&final_rect.x,
|
||||
&final_rect.y);
|
||||
|
||||
flipped_x =
|
||||
did_flip_horizontally (gdk_popup_layout_get_rect_anchor (layout),
|
||||
gdk_surface_get_popup_rect_anchor (priv->surface)) &&
|
||||
did_flip_horizontally (gdk_popup_layout_get_surface_anchor (layout),
|
||||
gdk_surface_get_popup_surface_anchor (priv->surface));
|
||||
flipped_y =
|
||||
did_flip_vertically (gdk_popup_layout_get_rect_anchor (layout),
|
||||
gdk_surface_get_popup_rect_anchor (priv->surface)) &&
|
||||
did_flip_vertically (gdk_popup_layout_get_surface_anchor (layout),
|
||||
gdk_surface_get_popup_surface_anchor (priv->surface));
|
||||
|
||||
gtk_widget_allocate (GTK_WIDGET (popover),
|
||||
gdk_surface_get_width (priv->surface),
|
||||
gdk_surface_get_height (priv->surface),
|
||||
-1, NULL);
|
||||
|
||||
priv->final_rect = final_rect;
|
||||
|
||||
switch (priv->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
priv->final_position = flipped_x ? GTK_POS_RIGHT : GTK_POS_LEFT;
|
||||
break;
|
||||
case GTK_POS_RIGHT:
|
||||
priv->final_position = flipped_x ? GTK_POS_LEFT : GTK_POS_RIGHT;
|
||||
break;
|
||||
case GTK_POS_TOP:
|
||||
priv->final_position = flipped_y ? GTK_POS_BOTTOM : GTK_POS_TOP;
|
||||
break;
|
||||
case GTK_POS_BOTTOM:
|
||||
priv->final_position = flipped_y ? GTK_POS_TOP : GTK_POS_BOTTOM;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
||||
gtk_widget_queue_draw (GTK_WIDGET (popover));
|
||||
}
|
||||
|
||||
static GdkPopupLayout *
|
||||
create_popup_layout (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GdkRectangle rect;
|
||||
GdkGravity parent_anchor;
|
||||
GdkGravity surface_anchor;
|
||||
GdkAnchorHints anchor_hints;
|
||||
GdkPopupLayout *layout;
|
||||
|
||||
gtk_widget_get_surface_allocation (priv->relative_to, &rect);
|
||||
if (priv->has_pointing_to)
|
||||
@ -341,46 +528,39 @@ move_to_rect (GtkPopover *popover)
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
gdk_surface_move_to_rect (priv->surface,
|
||||
&rect,
|
||||
parent_anchor,
|
||||
surface_anchor,
|
||||
anchor_hints,
|
||||
0, 0);
|
||||
layout = gdk_popup_layout_new (&rect,
|
||||
parent_anchor,
|
||||
surface_anchor);
|
||||
gdk_popup_layout_set_anchor_hints (layout, anchor_hints);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_move_resize (GtkPopover *popover)
|
||||
present_popup (GtkPopover *popover)
|
||||
{
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkRequisition req;
|
||||
GdkPopupLayout *layout;
|
||||
|
||||
if (priv->surface)
|
||||
{
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
|
||||
gdk_surface_resize (priv->surface, req.width, req.height);
|
||||
move_to_rect (popover);
|
||||
}
|
||||
layout = create_popup_layout (popover);
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (popover), NULL, &req);
|
||||
if (gdk_surface_present_popup (priv->surface,
|
||||
req.width, req.height,
|
||||
layout))
|
||||
update_popover_layout (popover, layout);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_native_check_resize (GtkNative *native)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (native);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkWidget *widget = GTK_WIDGET (popover);
|
||||
|
||||
if (!_gtk_widget_get_alloc_needed (widget))
|
||||
gtk_widget_ensure_allocate (widget);
|
||||
else if (gtk_widget_get_visible (widget))
|
||||
{
|
||||
gtk_popover_move_resize (popover);
|
||||
if (priv->surface)
|
||||
gtk_widget_allocate (GTK_WIDGET (popover),
|
||||
gdk_surface_get_width (priv->surface),
|
||||
gdk_surface_get_height (priv->surface),
|
||||
-1, NULL);
|
||||
}
|
||||
present_popup (popover);
|
||||
}
|
||||
|
||||
|
||||
@ -436,7 +616,8 @@ surface_state_changed (GtkWidget *widget)
|
||||
|
||||
if (changed_mask & GDK_SURFACE_STATE_WITHDRAWN)
|
||||
{
|
||||
if (priv->state & GDK_SURFACE_STATE_WITHDRAWN)
|
||||
if (priv->state & GDK_SURFACE_STATE_WITHDRAWN &&
|
||||
gtk_widget_is_visible (widget))
|
||||
gtk_widget_hide (widget);
|
||||
}
|
||||
}
|
||||
@ -467,36 +648,13 @@ surface_event (GdkSurface *surface,
|
||||
}
|
||||
|
||||
static void
|
||||
surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle *flipped_rect,
|
||||
GdkRectangle *final_rect,
|
||||
gboolean flipped_x,
|
||||
gboolean flipped_y,
|
||||
GtkWidget *widget)
|
||||
popup_layout_changed (GdkSurface *surface,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
priv->final_rect = *final_rect;
|
||||
|
||||
switch (priv->position)
|
||||
{
|
||||
case GTK_POS_LEFT:
|
||||
priv->final_position = flipped_x ? GTK_POS_RIGHT : GTK_POS_LEFT;
|
||||
break;
|
||||
case GTK_POS_RIGHT:
|
||||
priv->final_position = flipped_x ? GTK_POS_LEFT : GTK_POS_RIGHT;
|
||||
break;
|
||||
case GTK_POS_TOP:
|
||||
priv->final_position = flipped_y ? GTK_POS_BOTTOM : GTK_POS_TOP;
|
||||
break;
|
||||
case GTK_POS_BOTTOM:
|
||||
priv->final_position = flipped_y ? GTK_POS_TOP : GTK_POS_BOTTOM;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
update_popover_layout (popover, gdk_popup_layout_ref (priv->layout));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -612,7 +770,7 @@ gtk_popover_realize (GtkWidget *widget)
|
||||
g_signal_connect_swapped (priv->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
|
||||
g_signal_connect (priv->surface, "render", G_CALLBACK (surface_render), widget);
|
||||
g_signal_connect (priv->surface, "event", G_CALLBACK (surface_event), widget);
|
||||
g_signal_connect (priv->surface, "moved-to-rect", G_CALLBACK (surface_moved_to_rect), widget);
|
||||
g_signal_connect (priv->surface, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
|
||||
|
||||
@ -634,7 +792,7 @@ gtk_popover_unrealize (GtkWidget *widget)
|
||||
g_signal_handlers_disconnect_by_func (priv->surface, surface_size_changed, widget);
|
||||
g_signal_handlers_disconnect_by_func (priv->surface, surface_render, widget);
|
||||
g_signal_handlers_disconnect_by_func (priv->surface, surface_event, widget);
|
||||
g_signal_handlers_disconnect_by_func (priv->surface, surface_moved_to_rect, widget);
|
||||
g_signal_handlers_disconnect_by_func (priv->surface, popup_layout_changed, widget);
|
||||
gdk_surface_set_widget (priv->surface, NULL);
|
||||
gdk_surface_destroy (priv->surface);
|
||||
g_clear_object (&priv->surface);
|
||||
@ -648,7 +806,7 @@ gtk_popover_show (GtkWidget *widget)
|
||||
|
||||
_gtk_widget_set_visible_flag (widget, TRUE);
|
||||
gtk_widget_realize (widget);
|
||||
gtk_popover_native_check_resize (GTK_NATIVE (widget));
|
||||
present_popup (popover);
|
||||
gtk_widget_map (widget);
|
||||
|
||||
if (priv->autohide)
|
||||
@ -683,8 +841,8 @@ surface_transform_changed_cb (GtkWidget *widget,
|
||||
GtkPopover *popover = user_data;
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
move_to_rect (popover);
|
||||
g_clear_pointer (&priv->arrow_render_node, gsk_render_node_unref);
|
||||
if (priv->surface && gdk_surface_is_visible (priv->surface))
|
||||
present_popup (popover);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
@ -696,8 +854,7 @@ gtk_popover_map (GtkWidget *widget)
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
GtkWidget *child;
|
||||
|
||||
gdk_surface_show (priv->surface);
|
||||
move_to_rect (popover);
|
||||
present_popup (popover);
|
||||
|
||||
priv->surface_transform_changed_cb =
|
||||
gtk_widget_add_surface_transform_changed_callback (priv->relative_to,
|
||||
@ -755,6 +912,11 @@ gtk_popover_dispose (GObject *object)
|
||||
static void
|
||||
gtk_popover_finalize (GObject *object)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (object);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
g_clear_pointer (&priv->layout, gdk_popup_layout_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_popover_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -1096,8 +1258,6 @@ gtk_popover_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation child_alloc;
|
||||
int tail_height = priv->has_arrow ? TAIL_HEIGHT : 0;
|
||||
|
||||
gtk_popover_move_resize (popover);
|
||||
|
||||
switch (priv->final_position)
|
||||
{
|
||||
case GTK_POS_TOP:
|
||||
@ -1414,13 +1574,16 @@ gtk_popover_new (GtkWidget *relative_to)
|
||||
}
|
||||
|
||||
static void
|
||||
size_changed (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline,
|
||||
GtkPopover *popover)
|
||||
relative_to_size_changed (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline,
|
||||
GtkPopover *popover)
|
||||
{
|
||||
gtk_popover_move_resize (popover);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (priv->surface && gdk_surface_is_visible (priv->surface))
|
||||
present_popup (popover);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1487,7 +1650,9 @@ gtk_popover_set_relative_to (GtkPopover *popover,
|
||||
|
||||
if (priv->relative_to)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (priv->relative_to, size_changed, popover);
|
||||
g_signal_handlers_disconnect_by_func (priv->relative_to,
|
||||
relative_to_size_changed,
|
||||
popover);
|
||||
gtk_widget_unparent (GTK_WIDGET (popover));
|
||||
}
|
||||
|
||||
@ -1496,7 +1661,7 @@ gtk_popover_set_relative_to (GtkPopover *popover,
|
||||
if (priv->relative_to)
|
||||
{
|
||||
g_signal_connect_object (priv->relative_to, "size-allocate",
|
||||
G_CALLBACK (size_changed), popover, 0);
|
||||
G_CALLBACK (relative_to_size_changed), popover, 0);
|
||||
gtk_css_node_set_parent (gtk_widget_get_css_node (GTK_WIDGET (popover)),
|
||||
gtk_widget_get_css_node (relative_to));
|
||||
gtk_widget_set_parent (GTK_WIDGET (popover), relative_to);
|
||||
|
@ -110,16 +110,34 @@ gtk_tooltip_window_native_get_surface_transform (GtkNative *native,
|
||||
*y = margin.top + border.top + padding.top;
|
||||
}
|
||||
|
||||
static void
|
||||
move_to_rect (GtkTooltipWindow *window)
|
||||
static GdkPopupLayout *
|
||||
create_popup_layout (GtkTooltipWindow *window)
|
||||
{
|
||||
gdk_surface_move_to_rect (window->surface,
|
||||
&window->rect,
|
||||
window->rect_anchor,
|
||||
window->surface_anchor,
|
||||
window->anchor_hints,
|
||||
window->dx,
|
||||
window->dy);
|
||||
GdkPopupLayout *layout;
|
||||
|
||||
layout = gdk_popup_layout_new (&window->rect,
|
||||
window->rect_anchor,
|
||||
window->surface_anchor);
|
||||
gdk_popup_layout_set_anchor_hints (layout, window->anchor_hints);
|
||||
gdk_popup_layout_set_offset (layout, window->dx, window->dy);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
static void
|
||||
relayout_popup (GtkTooltipWindow *window)
|
||||
{
|
||||
GdkPopupLayout *layout;
|
||||
|
||||
if (!gtk_widget_get_visible (GTK_WIDGET (window)))
|
||||
return;
|
||||
|
||||
layout = create_popup_layout (window);
|
||||
gdk_surface_present_popup (window->surface,
|
||||
gdk_surface_get_width (window->surface),
|
||||
gdk_surface_get_height (window->surface),
|
||||
layout);
|
||||
gdk_popup_layout_unref (layout);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -131,7 +149,8 @@ gtk_tooltip_window_move_resize (GtkTooltipWindow *window)
|
||||
{
|
||||
gtk_widget_get_preferred_size (GTK_WIDGET (window), NULL, &req);
|
||||
gdk_surface_resize (window->surface, req.width, req.height);
|
||||
move_to_rect (window);
|
||||
|
||||
relayout_popup (window);
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,16 +225,6 @@ surface_event (GdkSurface *surface,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
surface_moved_to_rect (GdkSurface *surface,
|
||||
GdkRectangle *flipped_rect,
|
||||
GdkRectangle *final_rect,
|
||||
gboolean flipped_x,
|
||||
gboolean flipped_y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tooltip_window_realize (GtkWidget *widget)
|
||||
{
|
||||
@ -234,7 +243,6 @@ gtk_tooltip_window_realize (GtkWidget *widget)
|
||||
g_signal_connect_swapped (window->surface, "size-changed", G_CALLBACK (surface_size_changed), widget);
|
||||
g_signal_connect (window->surface, "render", G_CALLBACK (surface_render), widget);
|
||||
g_signal_connect (window->surface, "event", G_CALLBACK (surface_event), widget);
|
||||
g_signal_connect (window->surface, "moved-to-rect", G_CALLBACK (surface_moved_to_rect), widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->realize (widget);
|
||||
|
||||
@ -255,7 +263,6 @@ gtk_tooltip_window_unrealize (GtkWidget *widget)
|
||||
g_signal_handlers_disconnect_by_func (window->surface, surface_size_changed, widget);
|
||||
g_signal_handlers_disconnect_by_func (window->surface, surface_render, widget);
|
||||
g_signal_handlers_disconnect_by_func (window->surface, surface_event, widget);
|
||||
g_signal_handlers_disconnect_by_func (window->surface, surface_moved_to_rect, widget);
|
||||
gdk_surface_set_widget (window->surface, NULL);
|
||||
gdk_surface_destroy (window->surface);
|
||||
g_clear_object (&window->surface);
|
||||
@ -277,7 +284,7 @@ surface_transform_changed_cb (GtkWidget *widget,
|
||||
{
|
||||
GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget);
|
||||
|
||||
move_to_rect (window);
|
||||
relayout_popup (window);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
@ -287,10 +294,15 @@ static void
|
||||
gtk_tooltip_window_map (GtkWidget *widget)
|
||||
{
|
||||
GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget);
|
||||
GdkPopupLayout *layout;
|
||||
GtkWidget *child;
|
||||
|
||||
gdk_surface_show (window->surface);
|
||||
move_to_rect (window);
|
||||
layout = create_popup_layout (window);
|
||||
gdk_surface_present_popup (window->surface,
|
||||
gdk_surface_get_width (window->surface),
|
||||
gdk_surface_get_height (window->surface),
|
||||
layout);
|
||||
gdk_popup_layout_unref (layout);
|
||||
|
||||
window->surface_transform_changed_cb =
|
||||
gtk_widget_add_surface_transform_changed_callback (window->relative_to,
|
||||
@ -599,6 +611,6 @@ gtk_tooltip_window_position (GtkTooltipWindow *window,
|
||||
window->dx = dx;
|
||||
window->dy = dy;
|
||||
|
||||
move_to_rect (window);
|
||||
relayout_popup (window);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user