Commit 8a599b25 authored by Jonas Ådahl's avatar Jonas Ådahl
Browse files

gtk: Allocate everything from GtkNativeClass::layout

This changes allocation of the widget trees to happen as a side effect
to the GdkSurface::layout signal, which first passes the GtkNative
instance where it is then forwarded to the implementations of the
GtkNative interface.

The implementations of GtkNative are the ones doing the actual
gtk_widget_allocate(), and they do so in their GtkNativeClass::layout
function.
parent a798edc3
......@@ -158,6 +158,14 @@ gtk_drag_icon_native_check_resize (GtkNative *native)
gtk_drag_icon_move_resize (icon);
}
static void
gtk_drag_icon_native_layout (GtkNative *native,
int width,
int height)
{
gtk_widget_allocate (GTK_WIDGET (native), width, height, -1, NULL);
}
static void
gtk_drag_icon_native_init (GtkNativeInterface *iface)
{
......@@ -165,15 +173,7 @@ gtk_drag_icon_native_init (GtkNativeInterface *iface)
iface->get_renderer = gtk_drag_icon_native_get_renderer;
iface->get_surface_transform = gtk_drag_icon_native_get_surface_transform;
iface->check_resize = gtk_drag_icon_native_check_resize;
}
static void
surface_layout (GdkSurface *surface,
int width,
int height,
GtkWidget *widget)
{
gtk_widget_allocate (widget, width, height, -1, NULL);
iface->layout = gtk_drag_icon_native_layout;
}
static gboolean
......@@ -194,12 +194,13 @@ gtk_drag_icon_realize (GtkWidget *widget)
gdk_surface_set_widget (icon->surface, widget);
g_signal_connect (icon->surface, "layout", G_CALLBACK (surface_layout), widget);
g_signal_connect (icon->surface, "render", G_CALLBACK (surface_render), widget);
GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->realize (widget);
icon->renderer = gsk_renderer_new_for_surface (icon->surface);
gtk_native_realize (GTK_NATIVE (icon));
}
static void
......@@ -207,6 +208,8 @@ gtk_drag_icon_unrealize (GtkWidget *widget)
{
GtkDragIcon *icon = GTK_DRAG_ICON (widget);
gtk_native_unrealize (GTK_NATIVE (icon));
GTK_WIDGET_CLASS (gtk_drag_icon_parent_class)->unrealize (widget);
gsk_renderer_unrealize (icon->renderer);
......@@ -214,7 +217,6 @@ gtk_drag_icon_unrealize (GtkWidget *widget)
if (icon->surface)
{
g_signal_handlers_disconnect_by_func (icon->surface, surface_layout, widget);
g_signal_handlers_disconnect_by_func (icon->surface, surface_render, widget);
gdk_surface_set_widget (icon->surface, NULL);
}
......
......@@ -24,6 +24,15 @@
#include "gdk/gdk-private.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkcssnodeprivate.h"
typedef struct _GtkNativePrivate
{
gulong update_handler_id;
gulong layout_handler_id;
} GtkNativePrivate;
static GQuark quark_gtk_native_private;
/**
* SECTION:gtknative
......@@ -59,12 +68,108 @@ gtk_native_default_check_resize (GtkNative *self)
{
}
static void
gtk_native_default_layout (GtkNative *self,
int width,
int height)
{
}
static void
gtk_native_default_init (GtkNativeInterface *iface)
{
iface->get_renderer = gtk_native_default_get_renderer;
iface->get_surface_transform = gtk_native_default_get_surface_transform;
iface->check_resize = gtk_native_default_check_resize;
iface->layout = gtk_native_default_layout;
quark_gtk_native_private = g_quark_from_static_string ("gtk-native-private");
}
static void
frame_clock_update_cb (GdkFrameClock *clock,
GtkNative *native)
{
if (GTK_IS_ROOT (native))
gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (native)));
}
static void
gtk_native_layout (GtkNative *self,
int width,
int height)
{
return GTK_NATIVE_GET_IFACE (self)->layout (self, width, height);
}
static void
surface_layout_cb (GdkSurface *surface,
int width,
int height,
GtkNative *native)
{
gtk_native_layout (native, width, height);
if (gtk_widget_needs_allocate (GTK_WIDGET (native)))
gtk_native_queue_relayout (native);
}
static void
verify_priv_unrealized (gpointer user_data)
{
GtkNativePrivate *priv = user_data;
g_warn_if_fail (priv->update_handler_id == 0);
g_warn_if_fail (priv->layout_handler_id == 0);
g_free (priv);
}
void
gtk_native_realize (GtkNative *self)
{
GdkSurface *surface;
GdkFrameClock *clock;
GtkNativePrivate *priv;
g_return_if_fail (g_object_get_qdata (G_OBJECT (self),
quark_gtk_native_private) == NULL);
surface = gtk_native_get_surface (self);
clock = gdk_surface_get_frame_clock (surface);
g_return_if_fail (clock != NULL);
priv = g_new0 (GtkNativePrivate, 1);
priv->update_handler_id = g_signal_connect_after (clock, "update",
G_CALLBACK (frame_clock_update_cb),
self);
priv->layout_handler_id = g_signal_connect (surface, "layout",
G_CALLBACK (surface_layout_cb),
self);
g_object_set_qdata_full (G_OBJECT (self),
quark_gtk_native_private,
priv,
verify_priv_unrealized);
}
void
gtk_native_unrealize (GtkNative *self)
{
GtkNativePrivate *priv;
GdkSurface *surface;
GdkFrameClock *clock;
priv = g_object_get_qdata (G_OBJECT (self), quark_gtk_native_private);
g_return_if_fail (priv != NULL);
surface = gtk_native_get_surface (self);
clock = gdk_surface_get_frame_clock (surface);
g_return_if_fail (clock != NULL);
g_clear_signal_handler (&priv->update_handler_id, clock);
g_clear_signal_handler (&priv->layout_handler_id, surface);
g_object_set_qdata (G_OBJECT (self), quark_gtk_native_private, NULL);
}
/**
......@@ -157,3 +262,19 @@ gtk_native_get_for_surface (GdkSurface *surface)
return NULL;
}
void
gtk_native_queue_relayout (GtkNative *self)
{
GtkWidget *widget = GTK_WIDGET (self);
GdkSurface *surface;
GdkFrameClock *clock;
surface = gtk_widget_get_surface (widget);
clock = gtk_widget_get_frame_clock (widget);
if (clock == NULL)
return;
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
gdk_surface_request_layout (surface);
}
......@@ -34,6 +34,11 @@ G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
G_DECLARE_INTERFACE (GtkNative, gtk_native, GTK, NATIVE, GtkWidget)
GDK_AVAILABLE_IN_ALL
void gtk_native_realize (GtkNative *self);
GDK_AVAILABLE_IN_ALL
void gtk_native_unrealize (GtkNative *self);
GDK_AVAILABLE_IN_ALL
GtkNative * gtk_native_get_for_surface (GdkSurface *surface);
......
......@@ -24,8 +24,14 @@ struct _GtkNativeInterface
double *y);
void (* check_resize) (GtkNative *self);
void (* layout) (GtkNative *self,
int width,
int height);
};
void gtk_native_queue_relayout (GtkNative *native);
G_END_DECLS
#endif /* __GTK_NATIVE_PRIVATE_H__ */
......@@ -589,6 +589,23 @@ gtk_popover_native_check_resize (GtkNative *native)
present_popup (popover);
}
static void
gtk_popover_native_layout (GtkNative *native,
int width,
int height)
{
GtkPopover *popover = GTK_POPOVER (native);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
GtkWidget *widget = GTK_WIDGET (popover);
update_popover_layout (popover, gdk_popup_layout_ref (priv->layout));
if (gtk_widget_needs_allocate (widget))
gtk_widget_allocate (widget, width, height, -1, NULL);
else
gtk_widget_ensure_allocate (widget);
}
static gboolean
gtk_popover_has_mnemonic_modifier_pressed (GtkPopover *popover)
{
......@@ -766,20 +783,6 @@ popup_layout_changed (GdkSurface *surface,
update_popover_layout (popover, gdk_popup_layout_ref (priv->layout));
}
static void
surface_layout (GdkSurface *surface,
int width,
int height,
GtkWidget *widget)
{
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
update_popover_layout (popover, gdk_popup_layout_ref (priv->layout));
if (_gtk_widget_get_alloc_needed (widget))
gtk_widget_allocate (widget, width, height, -1, NULL);
}
static void
gtk_popover_activate_default (GtkPopover *popover)
{
......@@ -900,11 +903,12 @@ gtk_popover_realize (GtkWidget *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, "popup-layout-changed", G_CALLBACK (popup_layout_changed), widget);
g_signal_connect (priv->surface, "layout", G_CALLBACK (surface_layout), widget);
GTK_WIDGET_CLASS (gtk_popover_parent_class)->realize (widget);
priv->renderer = gsk_renderer_new_for_surface (priv->surface);
gtk_native_realize (GTK_NATIVE (popover));
}
static void
......@@ -913,6 +917,8 @@ gtk_popover_unrealize (GtkWidget *widget)
GtkPopover *popover = GTK_POPOVER (widget);
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
gtk_native_unrealize (GTK_NATIVE (popover));
GTK_WIDGET_CLASS (gtk_popover_parent_class)->unrealize (widget);
gsk_renderer_unrealize (priv->renderer);
......@@ -923,7 +929,6 @@ gtk_popover_unrealize (GtkWidget *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, popup_layout_changed, widget);
g_signal_handlers_disconnect_by_func (priv->surface, surface_layout, widget);
gdk_surface_set_widget (priv->surface, NULL);
gdk_surface_destroy (priv->surface);
g_clear_object (&priv->surface);
......@@ -1859,6 +1864,7 @@ gtk_popover_native_interface_init (GtkNativeInterface *iface)
iface->get_renderer = gtk_popover_native_get_renderer;
iface->get_surface_transform = gtk_popover_native_get_surface_transform;
iface->check_resize = gtk_popover_native_check_resize;
iface->layout = gtk_popover_native_layout;
}
static GtkBuildableIface *parent_buildable_iface;
......
......@@ -21,6 +21,7 @@
#include "gtkrootprivate.h"
#include "gtknative.h"
#include "gtknativeprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkwidgetprivate.h"
#include "gdk/gdk-private.h"
......@@ -43,10 +44,6 @@
* The obvious example of a #GtkRoot is #GtkWindow.
*/
static GQuark quark_restyle_pending;
static GQuark quark_layout_handler;
static GQuark quark_after_update_handler;
G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET,
g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_NATIVE))
......@@ -82,10 +79,6 @@ gtk_root_default_init (GtkRootInterface *iface)
iface->get_constraint_solver = gtk_root_default_get_constraint_solver;
iface->get_focus = gtk_root_default_get_focus;
iface->set_focus = gtk_root_default_set_focus;
quark_restyle_pending = g_quark_from_static_string ("gtk-root-restyle-pending");
quark_layout_handler = g_quark_from_static_string ("gtk-root-layout-handler");
quark_after_update_handler = g_quark_from_static_string ("gtk-root-after-update-handler");
}
/**
......@@ -163,152 +156,19 @@ gtk_root_get_focus (GtkRoot *self)
return GTK_ROOT_GET_IFACE (self)->get_focus (self);
}
static gboolean
gtk_root_needs_layout (GtkRoot *self)
{
if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending))
return TRUE;
return gtk_widget_needs_allocate (GTK_WIDGET (self));
}
static void
gtk_root_after_update_cb (GdkFrameClock *clock,
GtkRoot *self)
{
GtkWidget *widget = GTK_WIDGET (self);
/* We validate the style contexts in a single loop before even trying
* to handle resizes instead of doing validations inline.
* This is mostly necessary for compatibility reasons with old code,
* because both css_changed and size_allocate functions often change
* styles and so could cause infinite loops in this function.
*
* It's important to note that even an invalid style context returns
* sane values. So the result of an invalid style context will never be
* a program crash, but only a wrong layout or rendering.
*/
if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending))
{
gtk_css_node_validate (gtk_widget_get_css_node (widget));
}
}
static void
gtk_root_layout_cb (GdkSurface *surface,
int width,
int height,
GtkRoot *self)
{
GtkWidget *widget = GTK_WIDGET (self);
g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL);
/* we may be invoked with a container_resize_queue of NULL, because
* queue_resize could have been adding an extra idle function while
* the queue still got processed. we better just ignore such case
* than trying to explicitly work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
if (gtk_widget_needs_allocate (widget))
{
gtk_native_check_resize (GTK_NATIVE (self));
if (GTK_IS_WINDOW (widget))
{
GdkSeat *seat;
seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
if (seat)
{
GdkDevice *device;
GtkWidget *focus;
device = gdk_seat_get_pointer (seat);
focus = gtk_window_lookup_pointer_focus_widget (GTK_WINDOW (widget), device, NULL);
if (focus)
gdk_surface_request_motion (gtk_native_get_surface (gtk_widget_get_native (focus)));
}
}
}
if (gtk_root_needs_layout (self))
{
gdk_frame_clock_request_phase (gdk_surface_get_frame_clock (surface),
GDK_FRAME_CLOCK_PHASE_UPDATE);
gdk_surface_request_layout (surface);
}
}
void
gtk_root_start_layout (GtkRoot *self)
{
GdkSurface *surface;
GdkFrameClock *clock;
if (!gtk_root_needs_layout (self))
return;
surface = gtk_widget_get_surface (GTK_WIDGET (self));
clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
if (clock == NULL)
return;
if (!g_object_get_qdata (G_OBJECT (self), quark_layout_handler))
{
guint layout_handler;
guint after_update_handler;
after_update_handler =
g_signal_connect_after (clock, "update",
G_CALLBACK (gtk_root_after_update_cb), self);
g_object_set_qdata (G_OBJECT (self), quark_after_update_handler,
GINT_TO_POINTER (after_update_handler));
layout_handler =
g_signal_connect (surface, "layout",
G_CALLBACK (gtk_root_layout_cb), self);
g_object_set_qdata (G_OBJECT (self), quark_layout_handler,
GINT_TO_POINTER (layout_handler));
}
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_UPDATE);
gdk_surface_request_layout (surface);
gtk_native_queue_relayout (GTK_NATIVE (self));
}
void
gtk_root_stop_layout (GtkRoot *self)
{
GdkSurface *surface;
GdkFrameClock *clock;
guint layout_handler;
guint after_update_handler;
layout_handler =
GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self),
quark_layout_handler));
after_update_handler =
GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self),
quark_after_update_handler));
if (layout_handler == 0)
return;
surface = gtk_widget_get_surface (GTK_WIDGET (self));
clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
g_signal_handler_disconnect (surface, layout_handler);
g_signal_handler_disconnect (clock, after_update_handler);
g_object_set_qdata (G_OBJECT (self), quark_layout_handler, NULL);
g_object_set_qdata (G_OBJECT (self), quark_after_update_handler, NULL);
}
void
gtk_root_queue_restyle (GtkRoot *self)
{
if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending))
return;
g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, GINT_TO_POINTER (1));
gtk_root_start_layout (self);
}
......@@ -162,11 +162,6 @@ gtk_text_handle_present_surface (GtkTextHandle *handle)
MAX (req.height, 1),
layout);
gdk_popup_layout_unref (layout);
gtk_widget_allocate (widget,
gdk_surface_get_width (handle->surface),
gdk_surface_get_height (handle->surface),
-1, NULL);
}
static void
......@@ -181,6 +176,19 @@ gtk_text_handle_native_check_resize (GtkNative *native)
gtk_text_handle_present_surface (handle);
}
static void
gtk_text_handle_native_layout (GtkNative *native,
int width,
int height)
{
GtkWidget *widget = GTK_WIDGET (native);
if (_gtk_widget_get_alloc_needed (widget))
gtk_widget_allocate (widget, width, height, -1, NULL);
else
gtk_widget_ensure_allocate (widget);
}
static void
gtk_text_handle_native_interface_init (GtkNativeInterface *iface)
{
......@@ -188,6 +196,7 @@ gtk_text_handle_native_interface_init (GtkNativeInterface *iface)
iface->get_renderer = gtk_text_handle_native_get_renderer;
iface->get_surface_transform = gtk_text_handle_native_get_surface_transform;
iface->check_resize = gtk_text_handle_native_check_resize;
iface->layout = gtk_text_handle_native_layout;
}
static gboolean
......@@ -240,6 +249,8 @@ gtk_text_handle_realize (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->realize (widget);
handle->renderer = gsk_renderer_new_for_surface (handle->surface);
gtk_native_realize (GTK_NATIVE (handle));
}
static void
......@@ -247,6 +258,8 @@ gtk_text_handle_unrealize (GtkWidget *widget)
{
GtkTextHandle *handle = GTK_TEXT_HANDLE (widget);
gtk_native_unrealize (GTK_NATIVE (handle));
GTK_WIDGET_CLASS (gtk_text_handle_parent_class)->unrealize (widget);
gsk_renderer_unrealize (handle->renderer);
......
......@@ -152,14 +152,23 @@ gtk_tooltip_window_native_check_resize (GtkNative *native)
else if (gtk_widget_get_visible (widget))
{
gtk_tooltip_window_relayout (window);
if (window->surface)
gtk_widget_allocate (GTK_WIDGET (window),
gdk_surface_get_width (window->surface),
gdk_surface_get_height (window->surface),
-1, NULL);
}
}
static void
gtk_tooltip_window_native_layout (GtkNative *native,
int width,
int height)
{
GtkWidget *widget = GTK_WIDGET (native);
if (gtk_widget_needs_allocate (widget))
gtk_widget_allocate (widget, width, height, -1, NULL);
else
gtk_widget_ensure_allocate (widget);
}
static void
gtk_tooltip_window_native_init (GtkNativeInterface *iface)
{
......@@ -167,6 +176,7 @@ gtk_tooltip_window_native_init (GtkNativeInterface *iface)
iface->get_renderer = gtk_tooltip_window_native_get_renderer;
iface->get_surface_transform = gtk_tooltip_window_native_get_surface_transform;
iface->check_resize = gtk_tooltip_window_native_check_resize;
iface->layout = gtk_tooltip_window_native_layout;
}
static void
......@@ -223,6 +233,8 @@ gtk_tooltip_window_realize (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->realize (widget);
window->renderer = gsk_renderer_new_for_surface (window->surface);
gtk_native_realize (GTK_NATIVE (window));
}
static void
......@@ -230,6 +242,8 @@ gtk_tooltip_window_unrealize (GtkWidget *widget)
{
GtkTooltipWindow *window = GTK_TOOLTIP_WINDOW (widget);
gtk_native_unrealize (GTK_NATIVE (window));
GTK_WIDGET_CLASS (gtk_tooltip_window_parent_class)->unrealize (widget);
gsk_renderer_unrealize (window->renderer);
......
......@@ -56,6 +56,7 @@
#include "gtkrenderbackgroundprivate.h"
#include "gtkrenderborderprivate.h"
#include "gtkrootprivate.h"
#include "gtknativeprivate.h"
#include "gtkscrollable.h"
#include "gtksettingsprivate.h"
#include "gtkshortcut.h"
......@@ -10223,9 +10224,11 @@ gtk_widget_set_alloc_needed (GtkWidget *widget)
if (!priv->visible)
break;
if (GTK_IS_NATIVE (widget))
gtk_native_queue_relayout (GTK_NATIVE (widget));
if (!priv->parent && GTK_IS_ROOT (widget))
{
gtk_root_start_layout (GTK_ROOT (widget));
break;
}
......
This diff is collapsed.