Merge branch 'cherry-pick-4.6' into 'gtk-4-6'

Cherry-pick changes from main for gtk-4-6

See merge request GNOME/gtk!5025
This commit is contained in:
Matthias Clasen 2022-09-12 23:33:54 +00:00
commit 5fe9faf2e3
11 changed files with 308 additions and 114 deletions

View File

@ -1034,6 +1034,34 @@ gtk_emoji_chooser_show (GtkWidget *widget)
gtk_editable_set_text (GTK_EDITABLE (chooser->search_entry), "");
}
static EmojiSection *
find_section (GtkEmojiChooser *chooser,
GtkWidget *box)
{
if (box == chooser->recent.box)
return &chooser->recent;
else if (box == chooser->people.box)
return &chooser->people;
else if (box == chooser->body.box)
return &chooser->body;
else if (box == chooser->nature.box)
return &chooser->nature;
else if (box == chooser->food.box)
return &chooser->food;
else if (box == chooser->travel.box)
return &chooser->travel;
else if (box == chooser->activities.box)
return &chooser->activities;
else if (box == chooser->objects.box)
return &chooser->objects;
else if (box == chooser->symbols.box)
return &chooser->symbols;
else if (box == chooser->flags.box)
return &chooser->flags;
else
return NULL;
}
static EmojiSection *
find_next_section (GtkEmojiChooser *chooser,
GtkWidget *box,
@ -1105,81 +1133,111 @@ keynav_failed (GtkWidget *box,
GtkWidget *focus;
GtkWidget *child;
GtkWidget *sibling;
GtkAllocation alloc;
int i;
int column;
int n_columns = 7;
int child_x;
focus = gtk_root_get_focus (gtk_widget_get_root (box));
if (focus == NULL)
return FALSE;
/* determine the number of columns */
child_x = -1;
for (i = 0; i < 20; i++)
{
GtkAllocation alloc;
gtk_widget_get_allocation (GTK_WIDGET (gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (box), i)),
&alloc);
if (alloc.x > child_x)
child_x = alloc.x;
else
{
n_columns = i;
break;
}
}
n_columns = MAX (n_columns, 1);
child = gtk_widget_get_ancestor (focus, GTK_TYPE_EMOJI_CHOOSER_CHILD);
i = 0;
column = 0;
child_x = G_MAXINT;
for (sibling = gtk_widget_get_first_child (box);
sibling != child;
sibling;
sibling = gtk_widget_get_next_sibling (sibling))
i++;
{
if (!gtk_widget_get_child_visible (sibling))
continue;
column = i % n_columns;
gtk_widget_get_allocation (sibling, &alloc);
if (alloc.x < child_x)
column = 0;
else
column++;
child_x = alloc.x;
if (sibling == child)
break;
}
if (direction == GTK_DIR_DOWN)
{
next = find_next_section (chooser, box, TRUE);
if (next == NULL)
return FALSE;
i = 0;
for (sibling = gtk_widget_get_first_child (next->box);
sibling;
sibling = gtk_widget_get_next_sibling (sibling), i++)
{
next = find_section (chooser, box);
while (TRUE)
{
if (i == column)
next = find_next_section (chooser, next->box, TRUE);
if (next == NULL)
return FALSE;
i = 0;
child_x = G_MAXINT;
for (sibling = gtk_widget_get_first_child (next->box);
sibling;
sibling = gtk_widget_get_next_sibling (sibling))
{
gtk_widget_grab_focus (sibling);
return TRUE;
if (!gtk_widget_get_child_visible (sibling))
continue;
gtk_widget_get_allocation (sibling, &alloc);
if (alloc.x < child_x)
i = 0;
else
i++;
child_x = alloc.x;
if (i == column)
{
gtk_widget_grab_focus (sibling);
return TRUE;
}
}
}
}
else if (direction == GTK_DIR_UP)
{
next = find_next_section (chooser, box, FALSE);
if (next == NULL)
return FALSE;
next = find_section (chooser, box);
while (TRUE)
{
next = find_next_section (chooser, next->box, FALSE);
if (next == NULL)
return FALSE;
i = 0;
child = NULL;
for (sibling = gtk_widget_get_first_child (next->box);
sibling;
sibling = gtk_widget_get_next_sibling (sibling), i++)
{
if ((i % n_columns) == column)
child = sibling;
}
if (child)
{
gtk_widget_grab_focus (child);
return TRUE;
i = 0;
child_x = G_MAXINT;
child = NULL;
for (sibling = gtk_widget_get_first_child (next->box);
sibling;
sibling = gtk_widget_get_next_sibling (sibling))
{
if (!gtk_widget_get_child_visible (sibling))
continue;
gtk_widget_get_allocation (sibling, &alloc);
if (alloc.x < child_x)
i = 0;
else
i++;
child_x = alloc.x;
if (i == column)
child = sibling;
}
if (child)
{
gtk_widget_grab_focus (child);
return TRUE;
}
}
}

View File

@ -1082,30 +1082,19 @@ rewrite_event_for_toplevel (GdkEvent *event)
}
static gboolean
translate_event_coordinates (GdkEvent *event,
double *x,
double *y,
GtkWidget *widget)
translate_coordinates (double event_x,
double event_y,
double *x,
double *y,
GtkWidget *widget)
{
GtkWidget *event_widget;
GtkNative *native;
graphene_point_t p;
double event_x, event_y;
double native_x, native_y;
*x = *y = 0;
native = gtk_widget_get_native (widget);
if (!gdk_event_get_position (event, &event_x, &event_y))
return FALSE;
event_widget = gtk_get_event_widget (event);
native = gtk_widget_get_native (event_widget);
gtk_native_get_surface_transform (GTK_NATIVE (native), &native_x, &native_y);
event_x -= native_x;
event_y -= native_y;
if (!gtk_widget_compute_point (event_widget,
if (!gtk_widget_compute_point (GTK_WIDGET (native),
widget,
&GRAPHENE_POINT_INIT (event_x, event_y),
&p))
@ -1117,12 +1106,13 @@ translate_event_coordinates (GdkEvent *event,
return TRUE;
}
static void
void
gtk_synthesize_crossing_events (GtkRoot *toplevel,
GtkCrossingType crossing_type,
GtkWidget *old_target,
GtkWidget *new_target,
GdkEvent *event,
double surface_x,
double surface_y,
GdkCrossingMode mode,
GdkDrop *drop)
{
@ -1178,7 +1168,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
crossing.new_descendent = NULL;
}
check_crossing_invariants (widget, &crossing);
translate_event_coordinates (event, &x, &y, widget);
translate_coordinates (surface_x, surface_y, &x, &y, widget);
gtk_widget_handle_crossing (widget, &crossing, x, y);
if (crossing_type == GTK_CROSSING_POINTER)
gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT);
@ -1221,7 +1211,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
crossing.old_descendent = old_target ? crossing.new_descendent : NULL;
}
translate_event_coordinates (event, &x, &y, widget);
translate_coordinates (surface_x, surface_y, &x, &y, widget);
gtk_widget_handle_crossing (widget, &crossing, x, y);
if (crossing_type == GTK_CROSSING_POINTER)
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
@ -1388,7 +1378,7 @@ handle_pointing_event (GdkEvent *event)
old_target = update_pointer_focus_state (toplevel, event, NULL);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, old_target, NULL,
event, gdk_crossing_event_get_mode (event), NULL);
x, y, gdk_crossing_event_get_mode (event), NULL);
break;
case GDK_TOUCH_END:
case GDK_TOUCH_CANCEL:
@ -1401,7 +1391,7 @@ handle_pointing_event (GdkEvent *event)
old_target = update_pointer_focus_state (toplevel, event, NULL);
gtk_drop_begin_event (drop, GDK_DRAG_LEAVE);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, NULL,
event, GDK_CROSSING_NORMAL, drop);
x, y, GDK_CROSSING_NORMAL, drop);
gtk_drop_end_event (drop);
}
break;
@ -1428,7 +1418,7 @@ handle_pointing_event (GdkEvent *event)
sequence))
{
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, old_target, target,
event, GDK_CROSSING_NORMAL, NULL);
x, y, GDK_CROSSING_NORMAL, NULL);
}
gtk_window_maybe_update_cursor (toplevel, NULL, device);
@ -1439,7 +1429,7 @@ handle_pointing_event (GdkEvent *event)
GdkDrop *drop = gdk_dnd_event_get_drop (event);
gtk_drop_begin_event (drop, type);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_DROP, old_target, target,
event, GDK_CROSSING_NORMAL, gdk_dnd_event_get_drop (event));
x, y, GDK_CROSSING_NORMAL, gdk_dnd_event_get_drop (event));
gtk_drop_end_event (drop);
}
else if (type == GDK_TOUCH_BEGIN)
@ -1479,7 +1469,7 @@ handle_pointing_event (GdkEvent *event)
new_target = GTK_WIDGET (toplevel);
gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, target, new_target,
event, GDK_CROSSING_UNGRAB, NULL);
x, y, GDK_CROSSING_UNGRAB, NULL);
gtk_window_maybe_update_cursor (toplevel, NULL, device);
update_pointer_focus_state (toplevel, event, new_target);
}

View File

@ -1995,10 +1995,19 @@ gtk_paned_set_focus_child (GtkWidget *widget,
/* If there is one or more paned widgets between us and the
* focus widget, we want the topmost of those as last_focus
*/
for (w = last_focus; w != GTK_WIDGET (paned); w = gtk_widget_get_parent (w))
for (w = last_focus; w && w != GTK_WIDGET (paned); w = gtk_widget_get_parent (w))
if (GTK_IS_PANED (w))
last_focus = w;
if (w == NULL)
{
g_warning ("Error finding last focus widget of GtkPaned %p, "
"gtk_paned_set_focus_child was called on widget %p "
"which is not child of %p.",
widget, child, widget);
return;
}
focus_child = gtk_widget_get_focus_child (widget);
if (focus_child == paned->start_child)
gtk_paned_set_last_start_child_focus (paned, last_focus);

View File

@ -152,6 +152,15 @@ char * _gtk_elide_underscores (const char *original);
void setlocale_initialization (void);
void gtk_synthesize_crossing_events (GtkRoot *toplevel,
GtkCrossingType crossing_type,
GtkWidget *old_target,
GtkWidget *new_target,
double surface_x,
double surface_y,
GdkCrossingMode mode,
GdkDrop *drop);
G_END_DECLS
#endif /* __GTK_PRIVATE_H__ */

View File

@ -127,9 +127,7 @@ gtk_show_uri_full (GtkWindow *parent,
data->task = g_task_new (parent, cancellable, callback, user_data);
g_task_set_source_tag (data->task, gtk_show_uri);
if (parent)
gtk_window_export_handle (parent, window_handle_exported, data);
else
if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data))
window_handle_exported (parent, NULL, data);
}

View File

@ -1946,7 +1946,7 @@ gtk_text_init (GtkText *self)
g_signal_connect (priv->key_controller, "key-pressed",
G_CALLBACK (gtk_text_key_controller_key_pressed), self);
g_signal_connect_swapped (priv->key_controller, "im-update",
G_CALLBACK (gtk_im_context_reset), priv->im_context);
G_CALLBACK (gtk_text_schedule_im_reset), self);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
gtk_widget_add_controller (GTK_WIDGET (self), priv->key_controller);
@ -4276,6 +4276,7 @@ gtk_text_commit_cb (GtkIMContext *context,
{
gtk_text_enter_text (self, str);
gtk_text_obscure_mouse_cursor (self);
gtk_im_context_reset (context);
}
}
@ -4332,9 +4333,12 @@ gtk_text_delete_surrounding_cb (GtkIMContext *context,
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
if (priv->editable)
gtk_editable_delete_text (GTK_EDITABLE (self),
priv->current_pos + offset,
priv->current_pos + offset + n_chars);
{
gtk_editable_delete_text (GTK_EDITABLE (self),
priv->current_pos + offset,
priv->current_pos + offset + n_chars);
gtk_im_context_reset (context);
}
return TRUE;
}
@ -4349,10 +4353,8 @@ gtk_text_enter_text (GtkText *self,
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
int tmp_pos;
gboolean old_need_im_reset;
guint text_length;
old_need_im_reset = priv->need_im_reset;
priv->need_im_reset = FALSE;
if (priv->selection_bound != priv->current_pos)
@ -4370,8 +4372,6 @@ gtk_text_enter_text (GtkText *self,
tmp_pos = priv->current_pos;
gtk_editable_insert_text (GTK_EDITABLE (self), str, strlen (str), &tmp_pos);
gtk_text_set_selection_bounds (self, tmp_pos, tmp_pos);
priv->need_im_reset = old_need_im_reset;
}
/* All changes to priv->current_pos and priv->selection_bound

View File

@ -5516,17 +5516,8 @@ gtk_text_view_key_controller_im_update (GtkEventControllerKey *controller,
GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
GtkTextMark *insert;
GtkTextIter iter;
gboolean can_insert;
insert = gtk_text_buffer_get_insert (get_buffer (text_view));
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter, insert);
can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
priv->need_im_reset = TRUE;
if (can_insert)
gtk_text_view_reset_im_context (text_view);
}
static gboolean
@ -8486,6 +8477,7 @@ gtk_text_view_commit_handler (GtkIMContext *context,
gtk_text_view_commit_text (text_view, str);
gtk_text_view_reset_blink_time (text_view);
gtk_text_view_pend_cursor_blink (text_view);
gtk_im_context_reset (context);
}
static void
@ -8695,8 +8687,9 @@ gtk_text_view_delete_surrounding_handler (GtkIMContext *context,
gtk_text_iter_forward_chars (&start, offset);
gtk_text_iter_forward_chars (&end, offset + n_chars);
gtk_text_buffer_delete_interactive (priv->buffer, &start, &end,
priv->editable);
if (gtk_text_buffer_delete_interactive (priv->buffer, &start, &end,
priv->editable))
gtk_im_context_reset (context);
return TRUE;
}

View File

@ -436,6 +436,20 @@ gtk_tree_list_model_items_changed_cb (GListModel *model,
static void gtk_tree_list_row_destroy (GtkTreeListRow *row);
static void
gtk_tree_list_model_clear_node_children (TreeNode *node)
{
if (node->model)
{
g_signal_handlers_disconnect_by_func (node->model,
gtk_tree_list_model_items_changed_cb,
node);
g_clear_object (&node->model);
}
g_clear_pointer (&node->children, gtk_rb_tree_unref);
}
static void
gtk_tree_list_model_clear_node (gpointer data)
{
@ -444,15 +458,7 @@ gtk_tree_list_model_clear_node (gpointer data)
if (node->row)
gtk_tree_list_row_destroy (node->row);
if (node->model)
{
g_signal_handlers_disconnect_by_func (node->model,
gtk_tree_list_model_items_changed_cb,
node);
g_object_unref (node->model);
}
if (node->children)
gtk_rb_tree_unref (node->children);
gtk_tree_list_model_clear_node_children (node);
}
static void
@ -547,8 +553,7 @@ gtk_tree_list_model_collapse_node (GtkTreeListModel *self,
n_items = tree_node_get_n_children (node);
g_clear_pointer (&node->children, gtk_rb_tree_unref);
g_clear_object (&node->model);
gtk_tree_list_model_clear_node_children (node);
tree_node_mark_dirty (node);

View File

@ -271,7 +271,6 @@ gtk_tree_popover_init (GtkTreePopover *popover)
sw = gtk_scrolled_window_new ();
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_propagate_natural_width (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE);
gtk_popover_set_child (GTK_POPOVER (popover), sw);

View File

@ -5012,6 +5012,9 @@ synthesize_focus_change_events (GtkWindow *window,
GtkWidget *prev;
gboolean seen_ancestor;
if (old_focus == new_focus)
return;
if (old_focus && new_focus)
ancestor = gtk_widget_common_ancestor (old_focus, new_focus);
else
@ -6462,7 +6465,17 @@ gtk_window_update_pointer_focus_on_state_change (GtkWindow *window,
else if (focus->target == widget ||
gtk_widget_is_ancestor (focus->target, widget))
{
GtkWidget *old_target;
old_target = g_object_ref (focus->target);
gtk_pointer_focus_repick_target (focus);
gtk_synthesize_crossing_events (GTK_ROOT (window),
GTK_CROSSING_POINTER,
old_target, focus->target,
focus->x, focus->y,
GDK_CROSSING_NORMAL,
NULL);
g_object_unref (old_target);
}
gtk_pointer_focus_unref (focus);

View File

@ -252,6 +252,125 @@ test_remove_some (void)
g_object_unref (tree);
}
/* Test for https://gitlab.gnome.org/GNOME/gtk/-/issues/4595 */
typedef struct _DemoNode DemoNode;
struct _DemoNode {
GObject parent_instance;
char *value;
GListStore *children;
};
G_DECLARE_FINAL_TYPE (DemoNode, demo_node, DEMO, NODE, GObject);
G_DEFINE_TYPE (DemoNode, demo_node, G_TYPE_OBJECT);
static void
demo_node_init (DemoNode *node)
{
}
static void
demo_node_finalize (GObject *object)
{
g_free (DEMO_NODE (object)->value);
G_OBJECT_CLASS (demo_node_parent_class)->finalize (object);
}
static void
demo_node_class_init (DemoNodeClass *klass)
{
G_OBJECT_CLASS (klass)->finalize = demo_node_finalize;
}
static DemoNode *
demo_node_new (const char *value,
GListStore *children)
{
DemoNode *result;
result = g_object_new (demo_node_get_type(), NULL);
result->value = g_strdup (value);
if (children)
result->children = g_object_ref (children);
return result;
}
static GListStore *
create_model (void)
{
DemoNode *aa, *a, *b, *c;
GListStore *a_children, *root;
aa = demo_node_new ("aa", NULL);
a_children = g_list_store_new (demo_node_get_type ());
g_list_store_append (a_children, aa);
a = demo_node_new ("a", a_children);
b = demo_node_new ("b", NULL);
c = demo_node_new ("c", NULL);
root = g_list_store_new (demo_node_get_type ());
g_list_store_append (root, a);
g_list_store_append (root, b);
g_list_store_append (root, c);
g_object_unref (aa);
g_object_unref (a_children);
g_object_unref (a);
g_object_unref (b);
g_object_unref (c);
return root;
}
static GListModel *
model_children (gpointer item,
gpointer unused)
{
GListStore *children;
children = DEMO_NODE (item)->children;
if (children)
return G_LIST_MODEL (g_object_ref (children));
return NULL;
}
static void
test_collapse_change (void)
{
GListStore *model;
GtkTreeListModel *treemodel;
DemoNode *a, *ab;
GtkTreeListRow *row;
model = create_model ();
a = g_list_model_get_item (G_LIST_MODEL (model), 0);
treemodel = gtk_tree_list_model_new (G_LIST_MODEL (model),
FALSE,
FALSE,
model_children,
NULL,
NULL);
row = gtk_tree_list_model_get_row (treemodel, 0);
gtk_tree_list_row_set_expanded (row, TRUE);
gtk_tree_list_row_set_expanded (row, FALSE);
g_object_unref (row);
ab = demo_node_new ("ab", NULL);
g_list_store_append (a->children, ab);
g_object_unref (ab);
g_object_unref (treemodel);
g_object_unref (a);
}
int
main (int argc, char *argv[])
{
@ -263,6 +382,7 @@ main (int argc, char *argv[])
g_test_add_func ("/treelistmodel/expand", test_expand);
g_test_add_func ("/treelistmodel/remove_some", test_remove_some);
g_test_add_func ("/treelistmodel/collapse-change", test_collapse_change);
return g_test_run ();
}