mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 14:00:09 +00:00
widget: Add surface relative transform changed callback
Added two new private GtkWidget API: * gtk_widget_add_surface_transform_changed_callback() * gtk_widget_remove_surface_transform_changed_callback() The intention is to let the user know when a widget transform relative to the surface changes. It works by calculating the surface relative transform during allocation, and notifying the callbacks if it changed since last time. Each widget adds itself as a listener to its parent widget, thus will be triggered if a parents surface relative transform changes.
This commit is contained in:
parent
91bbe6ef95
commit
477ad2505b
256
gtk/gtkwidget.c
256
gtk/gtkwidget.c
@ -713,6 +713,9 @@ static void gtk_widget_update_input_shape (GtkWidget *widget);
|
||||
|
||||
static gboolean gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_class);
|
||||
|
||||
static void remove_parent_surface_transform_changed_listener (GtkWidget *widget);
|
||||
static void add_parent_surface_transform_changed_listener (GtkWidget *widget);
|
||||
|
||||
|
||||
/* --- variables --- */
|
||||
static gint GtkWidget_private_offset = 0;
|
||||
@ -2905,6 +2908,9 @@ gtk_widget_root (GtkWidget *widget)
|
||||
if (priv->context)
|
||||
gtk_style_context_set_display (priv->context, gtk_root_get_display (priv->root));
|
||||
|
||||
if (priv->surface_transform_changed_callbacks)
|
||||
add_parent_surface_transform_changed_listener (widget);
|
||||
|
||||
GTK_WIDGET_GET_CLASS (widget)->root (widget);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_ROOT]);
|
||||
@ -2922,6 +2928,9 @@ gtk_widget_unroot (GtkWidget *widget)
|
||||
g_assert (priv->root);
|
||||
g_assert (!priv->realized);
|
||||
|
||||
if (priv->parent_surface_transform_changed_parent)
|
||||
remove_parent_surface_transform_changed_listener (widget);
|
||||
|
||||
GTK_WIDGET_GET_CLASS (widget)->unroot (widget);
|
||||
|
||||
if (priv->context)
|
||||
@ -3586,6 +3595,249 @@ gtk_widget_disconnect_frame_clock (GtkWidget *widget)
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _GtkSurfaceTransformChangedCallbackInfo GtkSurfaceTransformChangedCallbackInfo;
|
||||
|
||||
struct _GtkSurfaceTransformChangedCallbackInfo
|
||||
{
|
||||
guint id;
|
||||
GtkSurfaceTransformChangedCallback callback;
|
||||
gpointer user_data;
|
||||
GDestroyNotify notify;
|
||||
};
|
||||
|
||||
static void
|
||||
surface_transform_changed_callback_info_destroy (GtkSurfaceTransformChangedCallbackInfo *info)
|
||||
{
|
||||
if (info->notify)
|
||||
info->notify (info->user_data);
|
||||
|
||||
g_slice_free (GtkSurfaceTransformChangedCallbackInfo, info);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_surface_transform_changed (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
graphene_matrix_t *surface_transform;
|
||||
GList *l;
|
||||
|
||||
if (priv->cached_surface_transform_valid)
|
||||
surface_transform = &priv->cached_surface_transform;
|
||||
else
|
||||
surface_transform = NULL;
|
||||
|
||||
for (l = priv->surface_transform_changed_callbacks; l;)
|
||||
{
|
||||
GtkSurfaceTransformChangedCallbackInfo *info = l->data;
|
||||
GList *l_next = l->next;
|
||||
|
||||
if (info->callback (widget,
|
||||
surface_transform,
|
||||
info->user_data) == G_SOURCE_REMOVE)
|
||||
{
|
||||
priv->surface_transform_changed_callbacks =
|
||||
g_list_delete_link (priv->surface_transform_changed_callbacks, l);
|
||||
surface_transform_changed_callback_info_destroy (info);
|
||||
}
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_surface_transform_changed_callbacks (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
GList *l;
|
||||
|
||||
for (l = priv->surface_transform_changed_callbacks; l;)
|
||||
{
|
||||
GtkSurfaceTransformChangedCallbackInfo *info = l->data;
|
||||
GList *l_next = l->next;
|
||||
|
||||
priv->surface_transform_changed_callbacks =
|
||||
g_list_delete_link (priv->surface_transform_changed_callbacks, l);
|
||||
surface_transform_changed_callback_info_destroy (info);
|
||||
|
||||
l = l_next;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sync_widget_surface_transform (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
gboolean was_valid;
|
||||
graphene_matrix_t prev_transform;
|
||||
|
||||
was_valid = priv->cached_surface_transform_valid;
|
||||
prev_transform = priv->cached_surface_transform;
|
||||
|
||||
if (GTK_IS_ROOT (widget))
|
||||
{
|
||||
gsk_transform_to_matrix (priv->transform,
|
||||
&priv->cached_surface_transform);
|
||||
priv->cached_surface_transform_valid = TRUE;
|
||||
}
|
||||
else if (!priv->root)
|
||||
{
|
||||
priv->cached_surface_transform_valid = FALSE;
|
||||
}
|
||||
else if (gtk_widget_compute_transform (widget, GTK_WIDGET (priv->root),
|
||||
&priv->cached_surface_transform))
|
||||
{
|
||||
priv->cached_surface_transform_valid = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Could not compute surface transform");
|
||||
priv->cached_surface_transform_valid = FALSE;
|
||||
}
|
||||
|
||||
if (was_valid != priv->cached_surface_transform_valid ||
|
||||
(was_valid && priv->cached_surface_transform_valid &&
|
||||
!graphene_matrix_equal (&priv->cached_surface_transform,
|
||||
&prev_transform)))
|
||||
notify_surface_transform_changed (widget);
|
||||
}
|
||||
|
||||
static guint surface_transform_changed_callback_id;
|
||||
|
||||
static gboolean
|
||||
parent_surface_transform_changed_cb (GtkWidget *parent,
|
||||
const graphene_matrix_t *transform,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (user_data);
|
||||
|
||||
sync_widget_surface_transform (widget);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_parent_surface_transform_changed_listener (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_assert (priv->parent_surface_transform_changed_parent);
|
||||
|
||||
gtk_widget_remove_surface_transform_changed_callback (
|
||||
priv->parent_surface_transform_changed_parent,
|
||||
priv->parent_surface_transform_changed_id);
|
||||
priv->parent_surface_transform_changed_id = 0;
|
||||
g_clear_object (&priv->parent_surface_transform_changed_parent);
|
||||
}
|
||||
|
||||
static void
|
||||
add_parent_surface_transform_changed_listener (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
GtkWidget *parent;
|
||||
|
||||
g_assert (!priv->parent_surface_transform_changed_parent);
|
||||
|
||||
parent = priv->parent;
|
||||
priv->parent_surface_transform_changed_id =
|
||||
gtk_widget_add_surface_transform_changed_callback (
|
||||
parent,
|
||||
parent_surface_transform_changed_cb,
|
||||
widget,
|
||||
NULL);
|
||||
priv->parent_surface_transform_changed_parent = g_object_ref (parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_add_surface_transform_changed_callback:
|
||||
* @widget: a #GtkWidget
|
||||
* @callback: a function to call when the surface transform changes
|
||||
* @user_data: data to pass to @callback
|
||||
* @notify: function to call to free @user_data when the callback is removed
|
||||
*
|
||||
* Invokes the callback whenever the surface relative transform of the widget
|
||||
* changes.
|
||||
*
|
||||
* Returns: an id for the connection of this callback. Remove the callback by
|
||||
* passing the id returned from this funcction to
|
||||
* gtk_widget_remove_surface_transform_changed_callback()
|
||||
*/
|
||||
guint
|
||||
gtk_widget_add_surface_transform_changed_callback (GtkWidget *widget,
|
||||
GtkSurfaceTransformChangedCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify)
|
||||
{
|
||||
GtkWidgetPrivate *priv;
|
||||
GtkSurfaceTransformChangedCallbackInfo *info;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
|
||||
g_return_val_if_fail (callback, 0);
|
||||
|
||||
priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
if (priv->parent && !priv->parent_surface_transform_changed_id)
|
||||
add_parent_surface_transform_changed_listener (widget);
|
||||
|
||||
if (!priv->surface_transform_changed_callbacks)
|
||||
sync_widget_surface_transform (widget);
|
||||
|
||||
info = g_slice_new0 (GtkSurfaceTransformChangedCallbackInfo);
|
||||
|
||||
info->id = ++surface_transform_changed_callback_id;
|
||||
info->callback = callback;
|
||||
info->user_data = user_data;
|
||||
info->notify = notify;
|
||||
|
||||
priv->surface_transform_changed_callbacks =
|
||||
g_list_prepend (priv->surface_transform_changed_callbacks, info);
|
||||
|
||||
return info->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_remove_surface_transform_changed_callback:
|
||||
* @widget: a #GtkWidget
|
||||
* @id: an id returned by gtk_widget_add_surface_transform_changed_callback()
|
||||
*
|
||||
* Removes a surface transform changed callback previously registered with
|
||||
* gtk_widget_add_surface_transform_changed_callback().
|
||||
*/
|
||||
void
|
||||
gtk_widget_remove_surface_transform_changed_callback (GtkWidget *widget,
|
||||
guint id)
|
||||
{
|
||||
GtkWidgetPrivate *priv;
|
||||
GList *l;
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
g_return_if_fail (id);
|
||||
|
||||
priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
for (l = priv->surface_transform_changed_callbacks; l; l = l->next)
|
||||
{
|
||||
GtkSurfaceTransformChangedCallbackInfo *info = l->data;
|
||||
|
||||
if (info->id == id)
|
||||
{
|
||||
priv->surface_transform_changed_callbacks =
|
||||
g_list_delete_link (priv->surface_transform_changed_callbacks, l);
|
||||
|
||||
surface_transform_changed_callback_info_destroy (info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priv->surface_transform_changed_callbacks)
|
||||
{
|
||||
if (priv->parent_surface_transform_changed_parent)
|
||||
remove_parent_surface_transform_changed_listener (widget);
|
||||
|
||||
g_signal_handler_disconnect (widget, priv->parent_changed_handler_id);
|
||||
priv->parent_changed_handler_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_realize:
|
||||
* @widget: a #GtkWidget
|
||||
@ -4200,6 +4452,9 @@ gtk_widget_allocate (GtkWidget *widget,
|
||||
|
||||
priv->transform = transform;
|
||||
|
||||
if (priv->surface_transform_changed_callbacks)
|
||||
sync_widget_surface_transform (widget);
|
||||
|
||||
if (!alloc_needed && !size_changed && !baseline_changed)
|
||||
{
|
||||
/* Still have to move the window... */
|
||||
@ -8125,6 +8380,7 @@ gtk_widget_real_destroy (GtkWidget *object)
|
||||
gtk_grab_remove (widget);
|
||||
|
||||
destroy_tick_callbacks (widget);
|
||||
destroy_surface_transform_changed_callbacks (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -41,6 +41,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef gboolean (*GtkSurfaceTransformChangedCallback) (GtkWidget *widget,
|
||||
const graphene_matrix_t *surface_transform,
|
||||
gpointer user_data);
|
||||
|
||||
#define GTK_STATE_FLAGS_BITS 14
|
||||
|
||||
struct _GtkWidgetPrivate
|
||||
@ -116,6 +120,14 @@ struct _GtkWidgetPrivate
|
||||
guint clock_tick_id;
|
||||
GList *tick_callbacks;
|
||||
|
||||
/* Surface relative transform updates callbacks */
|
||||
guint parent_surface_transform_changed_id;
|
||||
GtkWidget *parent_surface_transform_changed_parent;
|
||||
gulong parent_changed_handler_id;
|
||||
GList *surface_transform_changed_callbacks;
|
||||
gboolean cached_surface_transform_valid;
|
||||
graphene_matrix_t cached_surface_transform;
|
||||
|
||||
/* The widget's name. If the widget does not have a name
|
||||
* (the name is NULL), then its name (as returned by
|
||||
* "gtk_widget_get_name") is its class's name.
|
||||
@ -344,6 +356,15 @@ gboolean gtk_widget_run_controllers (GtkWidget
|
||||
GtkPropagationPhase phase);
|
||||
|
||||
|
||||
guint gtk_widget_add_surface_transform_changed_callback (GtkWidget *widget,
|
||||
GtkSurfaceTransformChangedCallback callback,
|
||||
gpointer user_data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void gtk_widget_remove_surface_transform_changed_callback (GtkWidget *widget,
|
||||
guint id);
|
||||
|
||||
|
||||
/* inline getters */
|
||||
|
||||
static inline GtkWidget *
|
||||
|
@ -35,7 +35,7 @@ gdk_pixbuf_req = '>= 2.30.0'
|
||||
introspection_req = '>= 1.39.0'
|
||||
wayland_proto_req = '>= 1.12'
|
||||
wayland_req = '>= 1.14.91'
|
||||
graphene_req = '>= 1.8.5'
|
||||
graphene_req = '>= 1.8.7'
|
||||
epoxy_req = '>= 1.4'
|
||||
cloudproviders_req = '>= 0.2.5'
|
||||
xkbcommon_req = '>= 0.2.0'
|
||||
|
Loading…
Reference in New Issue
Block a user