Merge branch 'clipboard-demo-fixes' into 'master'

Clipboard demo fixes

See merge request GNOME/gtk!1762
This commit is contained in:
Matthias Clasen 2020-04-26 02:13:33 +00:00
commit 796bc9bde1
11 changed files with 396 additions and 314 deletions

View File

@ -12,6 +12,7 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>
#include "demoimage.h"
static GtkWidget *window = NULL;
@ -93,147 +94,6 @@ paste_button_clicked (GtkWidget *button,
gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
}
static GdkPaintable *
get_image_paintable (GtkImage *image)
{
const gchar *icon_name;
GtkIconTheme *icon_theme;
GtkIconPaintable *icon;
switch (gtk_image_get_storage_type (image))
{
case GTK_IMAGE_PAINTABLE:
return g_object_ref (gtk_image_get_paintable (image));
case GTK_IMAGE_ICON_NAME:
icon_name = gtk_image_get_icon_name (image);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
icon = gtk_icon_theme_lookup_icon (icon_theme,
icon_name,
NULL,
48, 1,
gtk_widget_get_direction (GTK_WIDGET (image)),
0);
if (icon == NULL)
return NULL;
return GDK_PAINTABLE (icon);
case GTK_IMAGE_EMPTY:
case GTK_IMAGE_GICON:
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));
return NULL;
}
}
static void
drag_begin (GtkDragSource *source,
GdkDrag *drag,
GtkWidget *widget)
{
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (widget));
if (paintable)
{
gtk_drag_source_set_icon (source, paintable, -2, -2);
g_object_unref (paintable);
}
}
static GdkContentProvider *
prepare_drag (GtkDragSource *source,
double x,
double y,
GtkWidget *image)
{
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (image));
if (!GDK_IS_TEXTURE (paintable))
return NULL;
return gdk_content_provider_new_typed (GDK_TYPE_TEXTURE, paintable);
}
static gboolean
drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y,
GtkImage *image)
{
GdkTexture *texture = g_value_get_object (value);
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (texture));
return TRUE;
}
static void
copy_image (GSimpleAction *action,
GVariant *value,
gpointer data)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (data));
if (GDK_IS_TEXTURE (paintable))
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
if (paintable)
g_object_unref (paintable);
}
static void
paste_image_received (GObject *source,
GAsyncResult *result,
gpointer data)
{
GdkTexture *texture;
texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL);
if (texture == NULL)
return;
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
static void
paste_image (GSimpleAction *action,
GVariant *value,
gpointer data)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
gdk_clipboard_read_texture_async (clipboard, NULL, paste_image_received, data);
}
static void
pressed_cb (GtkGesture *gesture,
int n_press,
double x,
double y,
GtkWidget *image)
{
GtkWidget *popover;
GMenu *menu;
GMenuItem *item;
menu = g_menu_new ();
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
g_menu_append_item (menu, item);
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
g_menu_append_item (menu, item);
popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
gtk_widget_set_parent (popover, image);
gtk_popover_set_pointing_to (GTK_POPOVER (popover), &(GdkRectangle) { x, y, 1, 1});
gtk_popover_popup (GTK_POPOVER (popover));
g_object_unref (menu);
}
GtkWidget *
do_clipboard (GtkWidget *do_widget)
{
@ -243,14 +103,6 @@ do_clipboard (GtkWidget *do_widget)
GtkWidget *label;
GtkWidget *entry, *button;
GtkWidget *image;
GtkGesture *gesture;
GActionEntry entries[] = {
{ "copy", copy_image, NULL, NULL, NULL },
{ "paste", paste_image, NULL, NULL, NULL },
};
GActionGroup *actions;
GtkDragSource *source;
GtkDropTarget *dest;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
@ -320,62 +172,16 @@ do_clipboard (GtkWidget *do_widget)
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the first image */
image = gtk_image_new_from_icon_name ("dialog-warning");
gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
image = demo_image_new ("dialog-warning");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* make image a drag source */
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
/* accept drops on image */
dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
actions = G_ACTION_GROUP (g_simple_action_group_new ());
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image);
gtk_widget_insert_action_group (image, "clipboard", actions);
g_object_unref (actions);
/* Create the second image */
image = gtk_image_new_from_icon_name ("process-stop");
gtk_image_set_pixel_size (GTK_IMAGE (image), 48);
image = demo_image_new ("process-stop");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* make image a drag source */
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (source));
/* accept drops on image */
dest = gtk_drop_target_new (GDK_TYPE_TEXTURE, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (dest));
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
actions = G_ACTION_GROUP (g_simple_action_group_new ());
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), image);
gtk_widget_insert_action_group (image, "clipboard", actions);
g_object_unref (actions);
/* Create the third image */
image = demo_image_new ("weather-clear");
gtk_container_add (GTK_CONTAINER (hbox), image);
}
if (!gtk_widget_get_visible (window))

View File

@ -12,6 +12,10 @@
<gresource prefix="/builder">
<file>demo.ui</file>
</gresource>
<gresource prefix="/clipboard">
<file>demoimage.c</file>
<file>demoimage.h</file>
</gresource>
<gresource prefix="/css_accordion">
<file>css_accordion.css</file>
<file>reset.css</file>

259
demos/gtk-demo/demoimage.c Normal file
View File

@ -0,0 +1,259 @@
#include "demoimage.h"
#include <glib/gi18n.h>
struct _DemoImage {
GtkWidget parent_instance;
GtkWidget *image;
GtkWidget *popover;
};
enum {
PROP_ICON_NAME = 1
};
G_DEFINE_TYPE(DemoImage, demo_image, GTK_TYPE_WIDGET)
static GdkPaintable *
get_image_paintable (GtkImage *image)
{
const gchar *icon_name;
GtkIconTheme *icon_theme;
GtkIconPaintable *icon;
switch (gtk_image_get_storage_type (image))
{
case GTK_IMAGE_PAINTABLE:
return g_object_ref (gtk_image_get_paintable (image));
case GTK_IMAGE_ICON_NAME:
icon_name = gtk_image_get_icon_name (image);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
icon = gtk_icon_theme_lookup_icon (icon_theme,
icon_name,
NULL,
48, 1,
gtk_widget_get_direction (GTK_WIDGET (image)),
0);
if (icon == NULL)
return NULL;
return GDK_PAINTABLE (icon);
case GTK_IMAGE_EMPTY:
case GTK_IMAGE_GICON:
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));
return NULL;
}
}
static void
drag_begin (GtkDragSource *source,
GdkDrag *drag,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (demo->image));
if (paintable)
{
gtk_drag_icon_set_from_paintable (drag, paintable, -2, -2);
g_object_unref (paintable);
}
}
static GdkContentProvider *
prepare_drag (GtkDragSource *source,
double x,
double y,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
return gdk_content_provider_new_typed (GDK_TYPE_PAINTABLE, paintable);
}
static gboolean
drag_drop (GtkDropTarget *dest,
const GValue *value,
double x,
double y,
gpointer data)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest));
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = g_value_get_object (value);
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
return TRUE;
}
static void
copy_image (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
DemoImage *demo = DEMO_IMAGE (widget);
GdkPaintable *paintable = get_image_paintable (GTK_IMAGE (demo->image));
GValue value = G_VALUE_INIT;
g_value_init (&value, GDK_TYPE_PAINTABLE);
g_value_set_object (&value, paintable);
gdk_clipboard_set_value (clipboard, &value);
g_value_unset (&value);
if (paintable)
g_object_unref (paintable);
}
static void
paste_image (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (widget);
DemoImage *demo = DEMO_IMAGE (widget);
GdkContentProvider *content = gdk_clipboard_get_content (clipboard);
GValue value = G_VALUE_INIT;
GdkPaintable *paintable;
g_value_init (&value, GDK_TYPE_PAINTABLE);
if (!gdk_content_provider_get_value (content, &value, NULL))
return;
paintable = GDK_PAINTABLE (g_value_get_object (&value));
gtk_image_set_from_paintable (GTK_IMAGE (demo->image), paintable);
g_value_unset (&value);
}
static void
pressed_cb (GtkGesture *gesture,
int n_press,
double x,
double y,
gpointer data)
{
DemoImage *demo = DEMO_IMAGE (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)));
gtk_popover_popup (GTK_POPOVER (demo->popover));
}
static void
demo_image_init (DemoImage *demo)
{
GMenu *menu;
GMenuItem *item;
GtkDragSource *source;
GtkDropTarget *dest;
GtkGesture *gesture;
demo->image = gtk_image_new ();
gtk_image_set_pixel_size (GTK_IMAGE (demo->image), 48);
gtk_widget_set_parent (demo->image, GTK_WIDGET (demo));
menu = g_menu_new ();
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
g_menu_append_item (menu, item);
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
g_menu_append_item (menu, item);
demo->popover = gtk_popover_menu_new_from_model (G_MENU_MODEL (menu));
gtk_widget_set_parent (demo->popover, GTK_WIDGET (demo));
source = gtk_drag_source_new ();
g_signal_connect (source, "prepare", G_CALLBACK (prepare_drag), NULL);
g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (source));
dest = gtk_drop_target_new (GDK_TYPE_PAINTABLE, GDK_ACTION_COPY);
g_signal_connect (dest, "drop", G_CALLBACK (drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (demo), GTK_EVENT_CONTROLLER (gesture));
}
static void
demo_image_dispose (GObject *object)
{
DemoImage *demo = DEMO_IMAGE (object);
g_clear_pointer (&demo->image, gtk_widget_unparent);
g_clear_pointer (&demo->popover, gtk_widget_unparent);
G_OBJECT_CLASS (demo_image_parent_class)->dispose (object);
}
static void
demo_image_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
DemoImage *demo = DEMO_IMAGE (object);
switch (prop_id)
{
case PROP_ICON_NAME:
g_value_set_string (value, gtk_image_get_icon_name (GTK_IMAGE (demo->image)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_image_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
DemoImage *demo = DEMO_IMAGE (object);
switch (prop_id)
{
case PROP_ICON_NAME:
gtk_image_set_from_icon_name (GTK_IMAGE (demo->image),
g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
demo_image_class_init (DemoImageClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = demo_image_dispose;
object_class->get_property = demo_image_get_property;
object_class->set_property = demo_image_set_property;
g_object_class_install_property (object_class, PROP_ICON_NAME,
g_param_spec_string ("icon-name", "Icon name", "Icon name",
NULL, G_PARAM_READWRITE));
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, copy_image);
gtk_widget_class_install_action (widget_class, "clipboard.paste", NULL, paste_image);
}
GtkWidget *
demo_image_new (const char *icon_name)
{
return g_object_new (DEMO_TYPE_IMAGE, "icon-name", icon_name, NULL);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define DEMO_TYPE_IMAGE (demo_image_get_type ())
G_DECLARE_FINAL_TYPE(DemoImage, demo_image, DEMO, IMAGE, GtkWidget)
GtkWidget * demo_image_new (const char *icon_name);
G_END_DECLS

View File

@ -90,6 +90,7 @@ extra_demo_sources = files(['main.c',
'gtkgears.c',
'puzzlepiece.c',
'bluroverlay.c',
'demoimage.c',
'demotaggedentry.c'])
if harfbuzz_dep.found() and pangoft_dep.found()

View File

@ -46,7 +46,7 @@ gtk_css_widget_node_queue_callback (GtkWidget *widget,
GtkCssNode *node = user_data;
gtk_css_node_invalidate_frame_clock (node, TRUE);
gtk_window_queue_restyle (GTK_WINDOW (widget));
gtk_root_queue_restyle (GTK_ROOT (widget));
return G_SOURCE_CONTINUE;
}
@ -56,7 +56,7 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node)
{
GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
if (widget_node->widget && GTK_IS_ROOT (widget_node->widget))
if (GTK_IS_ROOT (widget_node->widget))
widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget,
gtk_css_widget_node_queue_callback,
node,

View File

@ -43,6 +43,9 @@
* The obvious example of a #GtkRoot is #GtkWindow.
*/
static GQuark quark_restyle_pending;
static GQuark quark_resize_handler;
G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET,
g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_NATIVE))
@ -78,6 +81,9 @@ 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_resize_handler = g_quark_from_static_string ("gtk-root-resize-handler");
}
/**
@ -154,3 +160,100 @@ 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_layout_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))
{
g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL);
gtk_css_node_validate (gtk_widget_get_css_node (widget));
}
/* 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_root_needs_layout (self))
gtk_root_stop_layout (self);
else
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_root_start_layout (GtkRoot *self)
{
GdkFrameClock *clock;
guint resize_handler;
if (g_object_get_qdata (G_OBJECT (self), quark_resize_handler))
return;
if (!gtk_root_needs_layout (self))
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
if (clock == NULL)
return;
resize_handler = g_signal_connect (clock, "layout",
G_CALLBACK (gtk_root_layout_cb), self);
g_object_set_qdata (G_OBJECT (self), quark_resize_handler, GINT_TO_POINTER (resize_handler));
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_root_stop_layout (GtkRoot *self)
{
GdkFrameClock *clock;
guint resize_handler;
resize_handler = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), quark_resize_handler));
if (resize_handler == 0)
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (self));
g_signal_handler_disconnect (clock, resize_handler);
g_object_set_qdata (G_OBJECT (self), quark_resize_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);
}

View File

@ -30,6 +30,10 @@ struct _GtkRootInterface
GtkConstraintSolver * gtk_root_get_constraint_solver (GtkRoot *self);
void gtk_root_start_layout (GtkRoot *self);
void gtk_root_stop_layout (GtkRoot *self);
void gtk_root_queue_restyle (GtkRoot *self);
G_END_DECLS
#endif /* __GTK_ROOT_PRIVATE_H__ */

View File

@ -10429,9 +10429,9 @@ gtk_widget_set_alloc_needed (GtkWidget *widget)
if (!priv->visible)
break;
if (GTK_IS_WINDOW (widget))
if (GTK_IS_ROOT (widget))
{
gtk_window_start_layout (GTK_WINDOW (widget));
gtk_root_start_layout (GTK_ROOT (widget));
break;
}

View File

@ -241,12 +241,8 @@ typedef struct
guint hide_on_close : 1;
guint in_emit_close_request : 1;
guint restyle_pending : 1;
GdkSurfaceTypeHint type_hint;
guint resize_handler;
GtkGesture *click_gesture;
GtkGesture *drag_gesture;
GtkGesture *bubble_drag_gesture;
@ -4016,9 +4012,6 @@ gtk_window_destroy (GtkWidget *widget)
if (priv->group)
gtk_window_group_remove_window (priv->group, window);
if (priv->restyle_pending)
priv->restyle_pending = FALSE;
GTK_WIDGET_CLASS (gtk_window_parent_class)->destroy (widget);
}
@ -4830,7 +4823,7 @@ gtk_window_realize (GtkWidget *widget)
GTK_WIDGET_CLASS (gtk_window_parent_class)->realize (widget);
gtk_window_start_layout (window);
gtk_root_start_layout (GTK_ROOT (window));
if (priv->renderer == NULL)
priv->renderer = gsk_renderer_new_for_surface (surface);
@ -4947,7 +4940,7 @@ gtk_window_unrealize (GtkWidget *widget)
g_signal_handlers_disconnect_by_func (surface, surface_render, widget);
g_signal_handlers_disconnect_by_func (surface, surface_event, widget);
gtk_window_stop_layout (window);
gtk_root_stop_layout (GTK_ROOT (window));
GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget);
@ -8111,100 +8104,3 @@ gtk_window_maybe_update_cursor (GtkWindow *window,
break;
}
}
static gboolean
gtk_window_needs_layout (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
if (priv->restyle_pending)
return TRUE;
return gtk_widget_needs_allocate (GTK_WIDGET (window));
}
static void
gtk_window_layout_cb (GdkFrameClock *clock,
GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GtkWidget *widget = GTK_WIDGET (window);
/* 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 (priv->restyle_pending)
{
priv->restyle_pending = FALSE;
gtk_css_node_validate (gtk_widget_get_css_node (widget));
}
/* 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 (window));
if (!gtk_window_needs_layout (window))
gtk_window_stop_layout (window);
else
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_window_start_layout (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GdkFrameClock *clock;
if (priv->resize_handler != 0)
return;
if (!gtk_window_needs_layout (window))
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (window));
if (clock == NULL)
return;
priv->resize_handler = g_signal_connect (clock, "layout",
G_CALLBACK (gtk_window_layout_cb), window);
gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
gtk_window_stop_layout (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
GdkFrameClock *clock;
if (priv->resize_handler == 0)
return;
clock = gtk_widget_get_frame_clock (GTK_WIDGET (window));
g_signal_handler_disconnect (clock, priv->resize_handler);
priv->resize_handler = 0;
}
void
gtk_window_queue_restyle (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
if (priv->restyle_pending)
return;
priv->restyle_pending = TRUE;
gtk_window_start_layout (window);
}

View File

@ -139,10 +139,6 @@ GtkWidget * gtk_window_pick_popover (GtkWindow *window,
void gtk_window_set_extra_input_region (GtkWindow *window,
cairo_region_t *region);
void gtk_window_start_layout (GtkWindow *window);
void gtk_window_stop_layout (GtkWindow *window);
void gtk_window_queue_restyle (GtkWindow *window);
G_END_DECLS