forked from AuroraMiddleware/gtk
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:
commit
5fe9faf2e3
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user