Compare commits
3 Commits
arraystore
...
wip/matthi
Author | SHA1 | Date | |
---|---|---|---|
|
825b2a4139 | ||
|
8a23649d40 | ||
|
bf367b219b |
@@ -44,7 +44,6 @@
|
||||
#include <gtk/gtkappchooserbutton.h>
|
||||
#include <gtk/gtkapplication.h>
|
||||
#include <gtk/gtkapplicationwindow.h>
|
||||
#include <gtk/gtkarraystore.h>
|
||||
#include <gtk/gtkaspectframe.h>
|
||||
#include <gtk/gtkassistant.h>
|
||||
#include <gtk/gtkbinlayout.h>
|
||||
|
137
gtk/gtkarrayimplprivate.h
Normal file
137
gtk/gtkarrayimplprivate.h
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef __GTK_ARRAY_IMPL_PRIVATE_H__
|
||||
#define __GTK_ARRAY_IMPL_PRIVATE_H__
|
||||
|
||||
|
||||
/* This is a dumbed-down GPtrArray, which takes some stack
|
||||
* space to use. When using this, the general case should always
|
||||
* be that the number of elements is lower than reserved_size.
|
||||
* The GPtrArray should only be used in extreme cases.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint reserved_size;
|
||||
guint len;
|
||||
void **stack_space;
|
||||
GPtrArray *ptr_array;
|
||||
|
||||
} GtkArray;
|
||||
|
||||
|
||||
static inline void
|
||||
gtk_array_init (GtkArray *self,
|
||||
void **stack_space,
|
||||
guint reserved_size)
|
||||
{
|
||||
self->reserved_size = reserved_size;
|
||||
self->len = 0;
|
||||
self->stack_space = stack_space;
|
||||
self->ptr_array = NULL;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
gtk_array_index (const GtkArray *self,
|
||||
guint index)
|
||||
{
|
||||
g_assert (index < self->len);
|
||||
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
return self->stack_space[index];
|
||||
|
||||
return g_ptr_array_index (self->ptr_array, index);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_add (GtkArray *self,
|
||||
void *element)
|
||||
{
|
||||
if (G_LIKELY (self->len < self->reserved_size))
|
||||
{
|
||||
self->stack_space[self->len] = element;
|
||||
self->len++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Need to fall back to the GPtrArray */
|
||||
if (G_UNLIKELY (!self->ptr_array))
|
||||
{
|
||||
self->ptr_array = g_ptr_array_new_full (self->len + 1, NULL);
|
||||
memcpy (self->ptr_array->pdata, self->stack_space, sizeof (void *) * self->len);
|
||||
self->ptr_array->len = self->len;
|
||||
}
|
||||
|
||||
g_ptr_array_add (self->ptr_array, element);
|
||||
self->len++; /* We still count self->len */
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_insert (GtkArray *self,
|
||||
guint index,
|
||||
void *element)
|
||||
{
|
||||
if (index >= self->len)
|
||||
{
|
||||
gtk_array_add (self, element);
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_LIKELY (self->len < self->reserved_size))
|
||||
{
|
||||
memmove (self->stack_space + index + 1, self->stack_space + index,
|
||||
sizeof (void *) * (self->len - index));
|
||||
self->stack_space[index] = element;
|
||||
self->len++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!self->ptr_array))
|
||||
{
|
||||
self->ptr_array = g_ptr_array_new_full (self->len + 1, NULL);
|
||||
memcpy (self->ptr_array->pdata, self->stack_space, sizeof (void *) * self->len);
|
||||
self->ptr_array->len = self->len;
|
||||
}
|
||||
|
||||
g_assert (self->ptr_array);
|
||||
g_ptr_array_insert (self->ptr_array, index, element);
|
||||
self->len++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_free (GtkArray *self,
|
||||
GDestroyNotify element_free_func)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
{
|
||||
if (element_free_func)
|
||||
{
|
||||
for (i = 0; i < self->len; i++)
|
||||
element_free_func (self->stack_space[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (self->ptr_array);
|
||||
|
||||
if (element_free_func)
|
||||
{
|
||||
for (i = 0; i < self->ptr_array->len; i++)
|
||||
element_free_func (g_ptr_array_index (self->ptr_array, i));
|
||||
}
|
||||
|
||||
g_ptr_array_free (self->ptr_array, TRUE);
|
||||
}
|
||||
|
||||
static inline void **
|
||||
gtk_array_get_data (GtkArray *self)
|
||||
{
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
return self->stack_space;
|
||||
|
||||
return self->ptr_array->pdata;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
@@ -1,287 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkarraystore.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GObject *
|
||||
#define GTK_VECTOR_FREE_FUNC g_object_unref
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkarraystore
|
||||
* @title: GtkArrayStore
|
||||
* @short_description: A simple array implementation of #GListModel
|
||||
*
|
||||
* #GtkArrayStore is a simple implementation of #GListModel that stores all
|
||||
* items in memory.
|
||||
*
|
||||
* It provides appending, deletions, and lookups in O(1) time and insertions
|
||||
* in O(N) time. it is implemented using an array.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GtkArrayStore:
|
||||
*
|
||||
* #GtkArrayStore is an opaque data structure and can only be accessed
|
||||
* using the following functions.
|
||||
**/
|
||||
|
||||
struct _GtkArrayStore
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GtkVector items;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static void gtk_array_store_iface_init (GListModelInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkArrayStore, gtk_array_store, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_array_store_iface_init));
|
||||
|
||||
static void
|
||||
gtk_array_store_dispose (GObject *object)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
gtk_vector_clear (&self->items);
|
||||
|
||||
G_OBJECT_CLASS (gtk_array_store_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE: /* construct-only */
|
||||
g_assert (g_type_is_a (g_value_get_gtype (value), G_TYPE_OBJECT));
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_class_init (GtkArrayStoreClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_array_store_dispose;
|
||||
object_class->get_property = gtk_array_store_get_property;
|
||||
object_class->set_property = gtk_array_store_set_property;
|
||||
|
||||
/**
|
||||
* GtkArrayStore:item-type:
|
||||
*
|
||||
* The type of items contained in this list self. Items must be
|
||||
* subclasses of #GObject.
|
||||
**/
|
||||
g_object_class_install_property (object_class, PROP_ITEM_TYPE,
|
||||
g_param_spec_gtype ("item-type", "", "", G_TYPE_OBJECT,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_array_store_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_array_store_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
return gtk_vector_get_size (&self->items);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_array_store_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
if (position >= gtk_vector_get_size (&self->items))
|
||||
return NULL;
|
||||
|
||||
return g_object_ref (gtk_vector_get (&self->items, position));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_array_store_get_item_type;
|
||||
iface->get_n_items = gtk_array_store_get_n_items;
|
||||
iface->get_item = gtk_array_store_get_item;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_init (GtkArrayStore *self)
|
||||
{
|
||||
gtk_vector_init (&self->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_new:
|
||||
* @item_type: the #GType of items in the list
|
||||
*
|
||||
* Creates a new #GtkArrayStore with items of type @item_type. @item_type
|
||||
* must be a subclass of #GObject.
|
||||
*
|
||||
* Returns: a new #GtkArrayStore
|
||||
*/
|
||||
GtkArrayStore *
|
||||
gtk_array_store_new (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_ARRAY_STORE,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_append:
|
||||
* @self: a #GtkArrayStore
|
||||
* @item: (type GObject): the new item
|
||||
*
|
||||
* Appends @item to @self. @item must be of type #GtkArrayStore:item-type.
|
||||
*
|
||||
* This function takes a ref on @item.
|
||||
*
|
||||
* Use gtk_array_store_splice() to append multiple items at the same time
|
||||
* efficiently.
|
||||
*/
|
||||
void
|
||||
gtk_array_store_append (GtkArrayStore *self,
|
||||
gpointer item)
|
||||
{
|
||||
guint position;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (item), self->item_type));
|
||||
|
||||
position = gtk_vector_get_size (&self->items);
|
||||
gtk_vector_append (&self->items, g_object_ref (item));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_remove_all:
|
||||
* @self: a #GtkArrayStore
|
||||
*
|
||||
* Removes all items from @self.
|
||||
*
|
||||
* Since: 2.44
|
||||
*/
|
||||
void
|
||||
gtk_array_store_remove_all (GtkArrayStore *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
|
||||
n_items = gtk_vector_get_size (&self->items);
|
||||
gtk_vector_clear (&self->items);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_splice:
|
||||
* @self: a #GtkArrayStore
|
||||
* @position: the position at which to make the change
|
||||
* @n_removals: the number of items to remove
|
||||
* @additions: (array length=n_additions) (element-type GObject): the items to add
|
||||
* @n_additions: the number of items to add
|
||||
*
|
||||
* Changes @self by removing @n_removals items and adding @n_additions
|
||||
* items to it. @additions must contain @n_additions items of type
|
||||
* #GtkArrayStore:item-type. %NULL is not permitted.
|
||||
*
|
||||
* This function is more efficient than gtk_array_store_insert() and
|
||||
* gtk_array_store_remove(), because it only emits
|
||||
* #GListModel::items-changed once for the change.
|
||||
*
|
||||
* This function takes a ref on each item in @additions.
|
||||
*
|
||||
* The parameters @position and @n_removals must be correct (ie:
|
||||
* @position + @n_removals must be less than or equal to the length of
|
||||
* the list at the time this function is called).
|
||||
*
|
||||
* Since: 2.44
|
||||
*/
|
||||
void
|
||||
gtk_array_store_splice (GtkArrayStore *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
gpointer *additions,
|
||||
guint n_additions)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
g_return_if_fail (position + n_removals >= position); /* overflow */
|
||||
g_return_if_fail (position + n_removals <= gtk_vector_get_size (&self->items));
|
||||
|
||||
for (i = 0; i < n_additions; i++)
|
||||
g_object_ref (additions[i]);
|
||||
|
||||
gtk_vector_splice (&self->items, position, n_removals, (GObject **) additions, n_additions);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_ARRAY_STORE_H__
|
||||
#define __GTK_ARRAY_STORE_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_ARRAY_STORE (gtk_array_store_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE(GtkArrayStore, gtk_array_store, GTK, ARRAY_STORE, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkArrayStore * gtk_array_store_new (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_append (GtkArrayStore *store,
|
||||
gpointer item);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_remove_all (GtkArrayStore *store);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_splice (GtkArrayStore *store,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
gpointer *additions,
|
||||
guint n_additions);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_ARRAY_STORE_H__ */
|
@@ -391,9 +391,9 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
|
||||
}
|
||||
|
||||
static void
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *tree_rules)
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkArray *tree_rules)
|
||||
{
|
||||
#ifdef VERIFY_TREE
|
||||
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (provider);
|
||||
@@ -407,9 +407,9 @@ verify_tree_match_results (GtkCssProvider *provider,
|
||||
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
||||
|
||||
for (j = 0; j < gtk_css_selector_matches_get_size (tree_rules); j++)
|
||||
for (j = 0; j < tree_rules->len; j++)
|
||||
{
|
||||
if (ruleset == gtk_css_selector_matches_get (tree_rules, j))
|
||||
if (ruleset == gtk_array_index (tree_rules, j))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -459,21 +459,22 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||
GtkCssRuleset *ruleset;
|
||||
guint j;
|
||||
int i;
|
||||
GtkCssSelectorMatches tree_rules;
|
||||
GtkArray tree_rules_array;
|
||||
GtkCssRuleset *rules_stack[32];
|
||||
|
||||
if (_gtk_css_selector_tree_is_empty (priv->tree))
|
||||
return;
|
||||
|
||||
gtk_css_selector_matches_init (&tree_rules);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules);
|
||||
gtk_array_init (&tree_rules_array, (void**)rules_stack, 32);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules_array);
|
||||
|
||||
if (!gtk_css_selector_matches_is_empty (&tree_rules))
|
||||
if (tree_rules_array.len > 0)
|
||||
{
|
||||
verify_tree_match_results (css_provider, node, &tree_rules);
|
||||
verify_tree_match_results (css_provider, node, &tree_rules_array);
|
||||
|
||||
for (i = gtk_css_selector_matches_get_size (&tree_rules) - 1; i >= 0; i--)
|
||||
for (i = tree_rules_array.len - 1; i >= 0; i--)
|
||||
{
|
||||
ruleset = gtk_css_selector_matches_get (&tree_rules, i);
|
||||
ruleset = gtk_array_index (&tree_rules_array, i);
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
continue;
|
||||
@@ -492,8 +493,9 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||
ruleset->styles[j].value);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_array_free (&tree_rules_array, NULL);
|
||||
}
|
||||
gtk_css_selector_matches_clear (&tree_rules);
|
||||
|
||||
if (change)
|
||||
*change = gtk_css_selector_tree_get_change_all (priv->tree, filter, node);
|
||||
|
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "gtkcssprovider.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtkarrayimplprivate.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1500
|
||||
@@ -151,14 +152,14 @@ gtk_css_selector_tree_get_matches (const GtkCssSelectorTree *tree)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_selector_matches_insert_sorted (GtkCssSelectorMatches *matches,
|
||||
gpointer data)
|
||||
gtk_array_insert_sorted (GtkArray *array,
|
||||
gpointer data)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < gtk_css_selector_matches_get_size (matches); i++)
|
||||
for (i = 0; i < array->len; i++)
|
||||
{
|
||||
gpointer elem = gtk_css_selector_matches_get (matches, i);
|
||||
gpointer elem = gtk_array_index (array, i);
|
||||
|
||||
if (data == elem)
|
||||
return;
|
||||
@@ -167,7 +168,7 @@ gtk_css_selector_matches_insert_sorted (GtkCssSelectorMatches *matches,
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_css_selector_matches_splice (matches, i, 0, (gpointer[1]) { data }, 1);
|
||||
gtk_array_insert (array, i, data);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -1876,7 +1877,7 @@ gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
|
||||
|
||||
static void
|
||||
gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
GtkCssSelectorMatches *results)
|
||||
GtkArray *results)
|
||||
{
|
||||
int i;
|
||||
gpointer *matches;
|
||||
@@ -1886,7 +1887,7 @@ gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
return;
|
||||
|
||||
for (i = 0; matches[i] != NULL; i++)
|
||||
gtk_css_selector_matches_insert_sorted (results, matches[i]);
|
||||
gtk_array_insert_sorted (results, matches[i]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1894,7 +1895,7 @@ gtk_css_selector_tree_match (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
gboolean match_filter,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *results)
|
||||
GtkArray *results)
|
||||
{
|
||||
const GtkCssSelectorTree *prev;
|
||||
GtkCssNode *child;
|
||||
@@ -1931,7 +1932,7 @@ void
|
||||
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *out_tree_rules)
|
||||
GtkArray *out_tree_rules)
|
||||
{
|
||||
const GtkCssSelectorTree *iter;
|
||||
|
||||
@@ -2116,7 +2117,8 @@ subdivide_infos (GByteArray *array,
|
||||
GHashTableIter iter;
|
||||
guint max_count;
|
||||
gpointer key, value;
|
||||
GtkCssSelectorMatches exact_matches;
|
||||
void *exact_matches_stack[8];
|
||||
GtkArray exact_matches_array;
|
||||
gint32 res;
|
||||
guint i;
|
||||
|
||||
@@ -2158,7 +2160,7 @@ subdivide_infos (GByteArray *array,
|
||||
matched_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
remaining_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
|
||||
gtk_css_selector_matches_init (&exact_matches);
|
||||
gtk_array_init (&exact_matches_array, (void**)exact_matches_stack, 8);
|
||||
for (i = 0; i < n_infos; i++)
|
||||
{
|
||||
GtkCssSelectorRuleSetInfo *info = infos[i];
|
||||
@@ -2169,7 +2171,7 @@ subdivide_infos (GByteArray *array,
|
||||
if (info->current_selector == NULL)
|
||||
{
|
||||
/* Matches current node */
|
||||
gtk_css_selector_matches_append (&exact_matches, info->match);
|
||||
gtk_array_add (&exact_matches_array, info->match);
|
||||
if (info->selector_match != NULL)
|
||||
*info->selector_match = GUINT_TO_POINTER (tree_offset);
|
||||
}
|
||||
@@ -2186,16 +2188,17 @@ subdivide_infos (GByteArray *array,
|
||||
}
|
||||
}
|
||||
|
||||
if (!gtk_css_selector_matches_is_empty (&exact_matches))
|
||||
if (exact_matches_array.len > 0)
|
||||
{
|
||||
gtk_css_selector_matches_append (&exact_matches, NULL); /* Null terminate */
|
||||
gtk_array_add (&exact_matches_array, NULL); /* Null terminate */
|
||||
res = array->len;
|
||||
g_byte_array_append (array, (guint8 *) gtk_css_selector_matches_get_data (&exact_matches),
|
||||
gtk_css_selector_matches_get_size (&exact_matches) * sizeof (gpointer));
|
||||
g_byte_array_append (array, (guint8 *)gtk_array_get_data (&exact_matches_array),
|
||||
exact_matches_array.len * sizeof (gpointer));
|
||||
|
||||
gtk_array_free (&exact_matches_array, NULL);
|
||||
}
|
||||
else
|
||||
res = GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET;
|
||||
gtk_css_selector_matches_clear (&exact_matches);
|
||||
get_tree (array, tree_offset)->matches_offset = res;
|
||||
|
||||
res = subdivide_infos (array, matched_infos, n_matched, tree_offset);
|
||||
|
@@ -21,12 +21,7 @@
|
||||
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||
#include "gtk/gtkcsstypesprivate.h"
|
||||
#include "gtk/gtkcssparserprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#define GTK_VECTOR_TYPE_NAME GtkCssSelectorMatches
|
||||
#define GTK_VECTOR_NAME gtk_css_selector_matches
|
||||
#define GTK_VECTOR_PREALLOC 32
|
||||
#include "gtk/gtkvectorimpl.c"
|
||||
#include "gtk/gtkarrayimplprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -50,8 +45,8 @@ int _gtk_css_selector_compare (const GtkCssSelector *a,
|
||||
void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree);
|
||||
void _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *out_tree_rules);
|
||||
GtkCssNode *node,
|
||||
GtkArray *out_tree_rules);
|
||||
GtkCssChange gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node);
|
||||
|
@@ -55,13 +55,6 @@
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE char *
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#define GTK_VECTOR_FREE_FUNC g_free
|
||||
#define GTK_VECTOR_TYPE_NAME GtkStrvBuilder
|
||||
#define GTK_VECTOR_NAME gtk_strv_builder
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkicontheme
|
||||
* @Short_description: Looking up icons by name
|
||||
@@ -2283,13 +2276,13 @@ real_choose_icon (GtkIconTheme *self,
|
||||
}
|
||||
|
||||
static void
|
||||
icon_name_list_add_icon (GtkStrvBuilder *icons,
|
||||
const gchar *dir_suffix,
|
||||
gchar *icon_name)
|
||||
icon_name_list_add_icon (GPtrArray *icons,
|
||||
const gchar *dir_suffix,
|
||||
gchar *icon_name)
|
||||
{
|
||||
if (dir_suffix)
|
||||
gtk_strv_builder_append (icons, g_strconcat (icon_name, dir_suffix, NULL));
|
||||
gtk_strv_builder_append (icons, icon_name);
|
||||
g_ptr_array_add (icons, g_strconcat (icon_name, dir_suffix, NULL));
|
||||
g_ptr_array_add (icons, icon_name);
|
||||
}
|
||||
|
||||
static GtkIconPaintable *
|
||||
@@ -2303,7 +2296,7 @@ choose_icon (GtkIconTheme *self,
|
||||
{
|
||||
gboolean has_regular = FALSE, has_symbolic = FALSE;
|
||||
GtkIconPaintable *icon;
|
||||
GtkStrvBuilder new_names;
|
||||
GPtrArray *new_names;
|
||||
const gchar *dir_suffix;
|
||||
guint i;
|
||||
|
||||
@@ -2334,70 +2327,73 @@ choose_icon (GtkIconTheme *self,
|
||||
|
||||
if ((flags & GTK_ICON_LOOKUP_FORCE_REGULAR) && has_symbolic)
|
||||
{
|
||||
gtk_strv_builder_init (&new_names);
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
for (i = 0; icon_names[i]; i++)
|
||||
{
|
||||
if (icon_name_is_symbolic (icon_names[i], -1))
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strndup (icon_names[i], strlen (icon_names[i]) - strlen ("-symbolic")));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strndup (icon_names[i], strlen (icon_names[i]) - strlen ("-symbolic")));
|
||||
else
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
}
|
||||
for (i = 0; icon_names[i]; i++)
|
||||
{
|
||||
if (icon_name_is_symbolic (icon_names[i], -1))
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
}
|
||||
g_ptr_array_add (new_names, NULL);
|
||||
|
||||
icon = real_choose_icon (self,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
(const gchar **) new_names->pdata,
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
}
|
||||
else if ((flags & GTK_ICON_LOOKUP_FORCE_SYMBOLIC) && has_regular)
|
||||
{
|
||||
gtk_strv_builder_init (&new_names);
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
for (i = 0; icon_names[i]; i++)
|
||||
{
|
||||
if (!icon_name_is_symbolic (icon_names[i], -1))
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strconcat (icon_names[i], "-symbolic", NULL));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strconcat (icon_names[i], "-symbolic", NULL));
|
||||
else
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
}
|
||||
for (i = 0; icon_names[i]; i++)
|
||||
{
|
||||
if (!icon_name_is_symbolic (icon_names[i], -1))
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
}
|
||||
g_ptr_array_add (new_names, NULL);
|
||||
|
||||
icon = real_choose_icon (self,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
(const gchar **) new_names->pdata,
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
}
|
||||
else if (dir_suffix)
|
||||
{
|
||||
gtk_strv_builder_init (&new_names);
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
for (i = 0; icon_names[i]; i++)
|
||||
{
|
||||
icon_name_list_add_icon (&new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
icon_name_list_add_icon (new_names, dir_suffix, g_strdup (icon_names[i]));
|
||||
}
|
||||
g_ptr_array_add (new_names, NULL);
|
||||
|
||||
icon = real_choose_icon (self,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
(const gchar **) new_names->pdata,
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -95,6 +95,7 @@
|
||||
#include "gdk/gdk-private.h"
|
||||
#include "gsk/gskprivate.h"
|
||||
#include "gsk/gskrendernodeprivate.h"
|
||||
#include "gtkarrayimplprivate.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
#include <locale.h>
|
||||
@@ -137,13 +138,6 @@
|
||||
#include "a11y/gtkaccessibility.h"
|
||||
#include "inspector/window.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GtkWidget *
|
||||
#define GTK_VECTOR_TYPE_NAME GtkWidgetStack
|
||||
#define GTK_VECTOR_NAME gtk_widget_stack
|
||||
#define GTK_VECTOR_FREE_FUNC g_object_unref
|
||||
#define GTK_VECTOR_PREALLOC 16
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
static GtkWindowGroup *gtk_main_get_window_group (GtkWidget *widget);
|
||||
|
||||
static gint pre_initialized = FALSE;
|
||||
@@ -1327,7 +1321,8 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
double x, y;
|
||||
GtkWidget *prev;
|
||||
gboolean seen_ancestor;
|
||||
GtkWidgetStack target_array;
|
||||
GtkArray target_array;
|
||||
GtkWidget *stack_targets[16];
|
||||
int i;
|
||||
|
||||
if (old_target == new_target)
|
||||
@@ -1381,19 +1376,19 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
widget = _gtk_widget_get_parent (widget);
|
||||
}
|
||||
|
||||
gtk_widget_stack_init (&target_array);
|
||||
gtk_array_init (&target_array, (void**)stack_targets, 16);
|
||||
for (widget = new_target; widget; widget = _gtk_widget_get_parent (widget))
|
||||
gtk_widget_stack_append (&target_array, g_object_ref (widget));
|
||||
gtk_array_add (&target_array, widget);
|
||||
|
||||
crossing.direction = GTK_CROSSING_IN;
|
||||
|
||||
seen_ancestor = FALSE;
|
||||
for (i = gtk_widget_stack_get_size (&target_array) - 1; i >= 0; i--)
|
||||
for (i = (int)target_array.len - 1; i >= 0; i--)
|
||||
{
|
||||
widget = gtk_widget_stack_get (&target_array, i);
|
||||
widget = gtk_array_index (&target_array, i);
|
||||
|
||||
if (i < gtk_widget_stack_get_size (&target_array) - 1)
|
||||
crossing.new_descendent = gtk_widget_stack_get (&target_array, i + 1);
|
||||
if (i < (int)target_array.len - 1)
|
||||
crossing.new_descendent = gtk_array_index (&target_array, i + 1);
|
||||
else
|
||||
crossing.new_descendent = NULL;
|
||||
|
||||
@@ -1422,7 +1417,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
|
||||
}
|
||||
|
||||
gtk_widget_stack_clear (&target_array);
|
||||
gtk_array_free (&target_array, NULL);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
@@ -1999,12 +1994,13 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
{
|
||||
gint handled_event = FALSE;
|
||||
GtkWidget *target = widget;
|
||||
GtkWidgetStack widget_array;
|
||||
GtkArray widget_array;
|
||||
GtkWidget *stack_widgets[16];
|
||||
int i;
|
||||
|
||||
/* First, propagate event down */
|
||||
gtk_widget_stack_init (&widget_array);
|
||||
gtk_widget_stack_append (&widget_array, g_object_ref (widget));
|
||||
gtk_array_init (&widget_array, (void**)stack_widgets, 16);
|
||||
gtk_array_add (&widget_array, g_object_ref (widget));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -2012,16 +2008,16 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
gtk_widget_stack_append (&widget_array, g_object_ref (widget));
|
||||
gtk_array_add (&widget_array, g_object_ref (widget));
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
}
|
||||
|
||||
i = gtk_widget_stack_get_size (&widget_array) - 1;
|
||||
i = widget_array.len - 1;
|
||||
for (;;)
|
||||
{
|
||||
widget = gtk_widget_stack_get (&widget_array, i);
|
||||
widget = gtk_array_index (&widget_array, i);
|
||||
|
||||
if (!_gtk_widget_is_sensitive (widget))
|
||||
{
|
||||
@@ -2054,9 +2050,9 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
for (i = 0; i < gtk_widget_stack_get_size (&widget_array); i++)
|
||||
for (i = 0; i < widget_array.len; i++)
|
||||
{
|
||||
widget = gtk_widget_stack_get (&widget_array, i);
|
||||
widget = gtk_array_index (&widget_array, i);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
@@ -2075,7 +2071,7 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_stack_clear (&widget_array);
|
||||
gtk_array_free (&widget_array, g_object_unref);
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
|
@@ -34,11 +34,6 @@
|
||||
|
||||
#include "gtk/gskpango.h"
|
||||
|
||||
#define GTK_VECTOR_NAME gtk_snapshot_nodes
|
||||
#define GTK_VECTOR_TYPE_NAME GtkSnapshotNodes
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GskRenderNode *
|
||||
#define GTK_VECTOR_FREE_FUNC gsk_render_node_unref
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtksnapshot
|
||||
@@ -59,85 +54,6 @@
|
||||
* use gtk_snapshot_new().
|
||||
*/
|
||||
|
||||
typedef struct _GtkSnapshotState GtkSnapshotState;
|
||||
|
||||
typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
GskRenderNode **nodes,
|
||||
guint n_nodes);
|
||||
|
||||
struct _GtkSnapshotState {
|
||||
guint start_node_index;
|
||||
guint n_nodes;
|
||||
|
||||
GskTransform * transform;
|
||||
|
||||
GtkSnapshotCollectFunc collect_func;
|
||||
union {
|
||||
struct {
|
||||
double opacity;
|
||||
} opacity;
|
||||
struct {
|
||||
double radius;
|
||||
} blur;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t child_bounds;
|
||||
} repeat;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
} clip;
|
||||
struct {
|
||||
GskRoundedRect bounds;
|
||||
} rounded_clip;
|
||||
struct {
|
||||
gsize n_shadows;
|
||||
GskShadow *shadows;
|
||||
GskShadow a_shadow; /* Used if n_shadows == 1 */
|
||||
} shadow;
|
||||
struct {
|
||||
GskBlendMode blend_mode;
|
||||
GskRenderNode *bottom_node;
|
||||
} blend;
|
||||
struct {
|
||||
double progress;
|
||||
GskRenderNode *start_node;
|
||||
} cross_fade;
|
||||
struct {
|
||||
char *message;
|
||||
} debug;
|
||||
} data;
|
||||
};
|
||||
|
||||
static void gtk_snapshot_state_clear (GtkSnapshotState *state);
|
||||
|
||||
#define GTK_VECTOR_NAME gtk_snapshot_states
|
||||
#define GTK_VECTOR_TYPE_NAME GtkSnapshotStates
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GtkSnapshotState
|
||||
#define GTK_VECTOR_FREE_FUNC gtk_snapshot_state_clear
|
||||
#define GTK_VECTOR_BY_VALUE 1
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/* This is a nasty little hack. We typedef GtkSnapshot to the fake object GdkSnapshot
|
||||
* so that we don't need to typecast between them.
|
||||
* After all, the GdkSnapshot only exist so poor language bindings don't trip. Hardcore
|
||||
* C code can just blatantly ignore such layering violations with a typedef.
|
||||
*/
|
||||
struct _GdkSnapshot {
|
||||
GObject parent_instance; /* it's really GdkSnapshot, but don't tell anyone! */
|
||||
|
||||
GtkSnapshotStates state_stack;
|
||||
GtkSnapshotNodes nodes;
|
||||
};
|
||||
|
||||
struct _GtkSnapshotClass {
|
||||
GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkSnapshot, gtk_snapshot, GDK_TYPE_SNAPSHOT)
|
||||
|
||||
static void
|
||||
@@ -145,11 +61,11 @@ gtk_snapshot_dispose (GObject *object)
|
||||
{
|
||||
GtkSnapshot *snapshot = GTK_SNAPSHOT (object);
|
||||
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
if (snapshot->state_stack)
|
||||
gsk_render_node_unref (gtk_snapshot_to_node (snapshot));
|
||||
|
||||
g_assert (gtk_snapshot_states_is_empty (&snapshot->state_stack));
|
||||
g_assert (gtk_snapshot_nodes_is_empty (&snapshot->nodes));
|
||||
g_assert (snapshot->state_stack == NULL);
|
||||
g_assert (snapshot->nodes == NULL);
|
||||
|
||||
G_OBJECT_CLASS (gtk_snapshot_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -196,15 +112,15 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
GskTransform *transform,
|
||||
GtkSnapshotCollectFunc collect_func)
|
||||
{
|
||||
const gsize n_states = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
const gsize n_states = snapshot->state_stack->len;
|
||||
GtkSnapshotState *state;
|
||||
|
||||
gtk_snapshot_states_set_size (&snapshot->state_stack, n_states + 1);
|
||||
state = gtk_snapshot_states_get (&snapshot->state_stack, n_states);
|
||||
g_array_set_size (snapshot->state_stack, n_states + 1);
|
||||
state = &g_array_index (snapshot->state_stack, GtkSnapshotState, n_states);
|
||||
|
||||
state->transform = gsk_transform_ref (transform);
|
||||
state->collect_func = collect_func;
|
||||
state->start_node_index = gtk_snapshot_nodes_get_size (&snapshot->nodes);
|
||||
state->start_node_index = snapshot->nodes->len;
|
||||
state->n_nodes = 0;
|
||||
|
||||
return state;
|
||||
@@ -213,21 +129,17 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_current_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
g_assert (snapshot->state_stack->len > 0);
|
||||
|
||||
g_assert (size > 0);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 1);
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 1);
|
||||
}
|
||||
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_previous_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
g_assert (snapshot->state_stack->len > 1);
|
||||
|
||||
g_assert (size > 1);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 2);
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 2);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -250,8 +162,9 @@ gtk_snapshot_new (void)
|
||||
|
||||
snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
|
||||
|
||||
gtk_snapshot_states_init (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_init (&snapshot->nodes);
|
||||
snapshot->state_stack = g_array_new (FALSE, TRUE, sizeof (GtkSnapshotState));
|
||||
g_array_set_clear_func (snapshot->state_stack, (GDestroyNotify)gtk_snapshot_state_clear);
|
||||
snapshot->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_render_node_unref);
|
||||
|
||||
gtk_snapshot_push_state (snapshot,
|
||||
NULL,
|
||||
@@ -1116,28 +1029,30 @@ gtk_snapshot_pop_one (GtkSnapshot *snapshot)
|
||||
guint state_index;
|
||||
GskRenderNode *node;
|
||||
|
||||
if (gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
if (snapshot->state_stack->len == 0)
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_pop() calls.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = gtk_snapshot_get_current_state (snapshot);
|
||||
state_index = gtk_snapshot_states_get_size (&snapshot->state_stack) - 1;
|
||||
state_index = snapshot->state_stack->len - 1;
|
||||
|
||||
if (state->collect_func)
|
||||
{
|
||||
node = state->collect_func (snapshot,
|
||||
state,
|
||||
(GskRenderNode **) gtk_snapshot_nodes_index (&snapshot->nodes, state->start_node_index),
|
||||
(GskRenderNode **) snapshot->nodes->pdata + state->start_node_index,
|
||||
state->n_nodes);
|
||||
|
||||
/* The collect func may not modify the state stack... */
|
||||
g_assert (state_index == gtk_snapshot_states_get_size (&snapshot->state_stack) - 1);
|
||||
g_assert (state_index == snapshot->state_stack->len - 1);
|
||||
|
||||
/* Remove all the state's nodes from the list of nodes */
|
||||
g_assert (state->start_node_index + state->n_nodes == gtk_snapshot_nodes_get_size (&snapshot->nodes));
|
||||
gtk_snapshot_nodes_splice (&snapshot->nodes, state->start_node_index, state->n_nodes, NULL, 0);
|
||||
g_assert (state->start_node_index + state->n_nodes == snapshot->nodes->len);
|
||||
g_ptr_array_remove_range (snapshot->nodes,
|
||||
snapshot->nodes->len - state->n_nodes,
|
||||
state->n_nodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1148,10 +1063,10 @@ gtk_snapshot_pop_one (GtkSnapshot *snapshot)
|
||||
/* move the nodes to the parent */
|
||||
previous_state = gtk_snapshot_get_previous_state (snapshot);
|
||||
previous_state->n_nodes += state->n_nodes;
|
||||
g_assert (previous_state->start_node_index + previous_state->n_nodes == gtk_snapshot_nodes_get_size (&snapshot->nodes));
|
||||
g_assert (previous_state->start_node_index + previous_state->n_nodes == snapshot->nodes->len);
|
||||
}
|
||||
|
||||
gtk_snapshot_states_splice (&snapshot->state_stack, state_index, 1, NULL, 0);
|
||||
g_array_remove_index (snapshot->state_stack, state_index);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -1166,7 +1081,7 @@ gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
|
||||
|
||||
if (current_state)
|
||||
{
|
||||
gtk_snapshot_nodes_append (&snapshot->nodes, node);
|
||||
g_ptr_array_add (snapshot->nodes, node);
|
||||
current_state->n_nodes ++;
|
||||
}
|
||||
else
|
||||
@@ -1247,14 +1162,16 @@ gtk_snapshot_to_node (GtkSnapshot *snapshot)
|
||||
result = gtk_snapshot_pop_internal (snapshot);
|
||||
|
||||
/* We should have exactly our initial state */
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
if (snapshot->state_stack->len > 0)
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %zu states remaining.",
|
||||
gtk_snapshot_states_get_size (&snapshot->state_stack));
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %u states remaining.", snapshot->state_stack->len);
|
||||
}
|
||||
|
||||
gtk_snapshot_states_clear (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_clear (&snapshot->nodes);
|
||||
g_array_free (snapshot->state_stack, TRUE);
|
||||
g_ptr_array_free (snapshot->nodes, TRUE);
|
||||
|
||||
snapshot->state_stack = NULL;
|
||||
snapshot->nodes = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@@ -24,6 +24,76 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkSnapshotState GtkSnapshotState;
|
||||
|
||||
typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
GskRenderNode **nodes,
|
||||
guint n_nodes);
|
||||
|
||||
struct _GtkSnapshotState {
|
||||
guint start_node_index;
|
||||
guint n_nodes;
|
||||
|
||||
GskTransform * transform;
|
||||
|
||||
GtkSnapshotCollectFunc collect_func;
|
||||
union {
|
||||
struct {
|
||||
double opacity;
|
||||
} opacity;
|
||||
struct {
|
||||
double radius;
|
||||
} blur;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t child_bounds;
|
||||
} repeat;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
} clip;
|
||||
struct {
|
||||
GskRoundedRect bounds;
|
||||
} rounded_clip;
|
||||
struct {
|
||||
gsize n_shadows;
|
||||
GskShadow *shadows;
|
||||
GskShadow a_shadow; /* Used if n_shadows == 1 */
|
||||
} shadow;
|
||||
struct {
|
||||
GskBlendMode blend_mode;
|
||||
GskRenderNode *bottom_node;
|
||||
} blend;
|
||||
struct {
|
||||
double progress;
|
||||
GskRenderNode *start_node;
|
||||
} cross_fade;
|
||||
struct {
|
||||
char *message;
|
||||
} debug;
|
||||
} data;
|
||||
};
|
||||
|
||||
/* This is a nasty little hack. We typedef GtkSnapshot to the fake object GdkSnapshot
|
||||
* so that we don't need to typecast between them.
|
||||
* After all, the GdkSnapshot only exist so poor language bindings don't trip. Hardcore
|
||||
* C code can just blatantly ignore such layering violations with a typedef.
|
||||
*/
|
||||
struct _GdkSnapshot {
|
||||
GObject parent_instance; /* it's really GdkSnapshot, but don't tell anyone! */
|
||||
|
||||
GArray *state_stack;
|
||||
GPtrArray *nodes;
|
||||
};
|
||||
|
||||
struct _GtkSnapshotClass {
|
||||
GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
|
||||
};
|
||||
|
||||
void gtk_snapshot_append_text (GtkSnapshot *snapshot,
|
||||
PangoFont *font,
|
||||
PangoGlyphString *glyphs,
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "gtkbuilderprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkbitset.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkstringlist
|
||||
@@ -145,23 +146,6 @@ gtk_string_object_class_init (GtkStringObjectClass *class)
|
||||
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
gtk_string_object_new_take (char *string)
|
||||
{
|
||||
GtkStringObject *obj;
|
||||
|
||||
obj = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
|
||||
obj->string = string;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
gtk_string_object_new (const char *string)
|
||||
{
|
||||
return gtk_string_object_new_take (g_strdup (string));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_object_get_string:
|
||||
* @self: a #GtkStringObject
|
||||
@@ -182,7 +166,8 @@ struct _GtkStringList
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSequence *items;
|
||||
GPtrArray *items;
|
||||
GtkBitset *objects;
|
||||
};
|
||||
|
||||
struct _GtkStringListClass
|
||||
@@ -201,7 +186,56 @@ gtk_string_list_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkStringList *self = GTK_STRING_LIST (list);
|
||||
|
||||
return g_sequence_get_length (self->items);
|
||||
return self->items->len;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
IS_STRING (gpointer item)
|
||||
{
|
||||
return GPOINTER_TO_INT (item) & 0x1;
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
TO_STRING (gpointer item)
|
||||
{
|
||||
return GINT_TO_POINTER (GPOINTER_TO_INT (item) & ~0x1);
|
||||
}
|
||||
|
||||
static inline gpointer
|
||||
MAKE_STRING (const char *str)
|
||||
{
|
||||
return GINT_TO_POINTER (GPOINTER_TO_INT (str) | 0x1);
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
find_unused_object (GtkStringList *self)
|
||||
{
|
||||
GtkBitsetIter iter;
|
||||
guint position;
|
||||
gpointer item;
|
||||
|
||||
if (gtk_bitset_iter_init_first (&iter, self->objects, &position))
|
||||
{
|
||||
do
|
||||
{
|
||||
item = g_ptr_array_index (self->items, position);
|
||||
g_assert (!IS_STRING (item));
|
||||
if (G_OBJECT (item)->ref_count == 1)
|
||||
{
|
||||
GtkStringObject *obj;
|
||||
|
||||
obj = GTK_STRING_OBJECT (item);
|
||||
g_ptr_array_index (self->items, position) = MAKE_STRING (obj->string);
|
||||
obj->string = NULL;
|
||||
|
||||
gtk_bitset_remove (self->objects, position);
|
||||
|
||||
return obj;
|
||||
}
|
||||
} while (gtk_bitset_iter_next (&iter, &position));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
@@ -209,14 +243,30 @@ gtk_string_list_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkStringList *self = GTK_STRING_LIST (list);
|
||||
GSequenceIter *iter;
|
||||
gpointer item;
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
|
||||
if (g_sequence_iter_is_end (iter))
|
||||
if (position >= self->items->len)
|
||||
return NULL;
|
||||
else
|
||||
return g_object_ref (g_sequence_get (iter));
|
||||
|
||||
item = g_ptr_array_index (self->items, position);
|
||||
if (IS_STRING (item))
|
||||
{
|
||||
GtkStringObject *obj;
|
||||
|
||||
obj = find_unused_object (self);
|
||||
if (!obj)
|
||||
obj = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
|
||||
|
||||
obj->string = TO_STRING (item);
|
||||
g_ptr_array_index (self->items, position) = obj;
|
||||
gtk_bitset_add (self->objects, position);
|
||||
|
||||
item = obj;
|
||||
}
|
||||
|
||||
g_print ("live string objects: %lu\n", gtk_bitset_get_size (self->objects));
|
||||
|
||||
return g_object_ref (item);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -323,7 +373,7 @@ item_end_element (GtkBuildableParseContext *context,
|
||||
g_string_assign (data->string, translated);
|
||||
}
|
||||
|
||||
g_sequence_append (data->list->items, gtk_string_object_new (data->string->str));
|
||||
g_ptr_array_add (data->list->items, MAKE_STRING (g_strdup (data->string->str)));
|
||||
}
|
||||
|
||||
data->translatable = FALSE;
|
||||
@@ -403,7 +453,8 @@ gtk_string_list_dispose (GObject *object)
|
||||
{
|
||||
GtkStringList *self = GTK_STRING_LIST (object);
|
||||
|
||||
g_clear_pointer (&self->items, g_sequence_free);
|
||||
g_clear_pointer (&self->items, g_ptr_array_unref);
|
||||
g_clear_pointer (&self->objects, gtk_bitset_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_string_list_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -416,10 +467,20 @@ gtk_string_list_class_init (GtkStringListClass *class)
|
||||
gobject_class->dispose = gtk_string_list_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
free_string_or_object (gpointer data)
|
||||
{
|
||||
if (IS_STRING (data))
|
||||
g_free (TO_STRING (data));
|
||||
else
|
||||
g_object_unref (data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_list_init (GtkStringList *self)
|
||||
{
|
||||
self->items = g_sequence_new (g_object_unref);
|
||||
self->items = g_ptr_array_new_full (32, free_string_or_object);
|
||||
self->objects = gtk_bitset_new_empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -468,39 +529,36 @@ gtk_string_list_splice (GtkStringList *self,
|
||||
guint n_removals,
|
||||
const char * const *additions)
|
||||
{
|
||||
GSequenceIter *it;
|
||||
guint add, n_items;
|
||||
guint n_items;
|
||||
guint i;
|
||||
guint n_additions;
|
||||
gpointer item;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST (self));
|
||||
g_return_if_fail (position + n_removals >= position); /* overflow */
|
||||
|
||||
n_items = g_sequence_get_length (self->items);
|
||||
n_items = self->items->len;
|
||||
g_return_if_fail (position + n_removals <= n_items);
|
||||
|
||||
it = g_sequence_get_iter_at_pos (self->items, position);
|
||||
|
||||
if (n_removals)
|
||||
{
|
||||
GSequenceIter *end;
|
||||
|
||||
end = g_sequence_iter_move (it, n_removals);
|
||||
g_sequence_remove_range (it, end);
|
||||
|
||||
it = end;
|
||||
}
|
||||
for (i = 0; i < n_removals; i++)
|
||||
g_ptr_array_remove_index (self->items, position);
|
||||
|
||||
if (additions)
|
||||
{
|
||||
for (add = 0; additions[add]; add++)
|
||||
for (i = 0; additions[i]; i++)
|
||||
{
|
||||
g_sequence_insert_before (it, gtk_string_object_new (additions[add]));
|
||||
item = MAKE_STRING (g_strdup (additions[i]));
|
||||
g_ptr_array_insert (self->items, position + i, item);
|
||||
}
|
||||
n_additions = i;
|
||||
}
|
||||
else
|
||||
add = 0;
|
||||
n_additions = 0;
|
||||
|
||||
if (n_removals || add)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, add);
|
||||
gtk_bitset_slice (self->objects, position, n_removals, n_additions);
|
||||
|
||||
if (n_removals || n_additions)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,11 +576,13 @@ gtk_string_list_append (GtkStringList *self,
|
||||
const char *string)
|
||||
{
|
||||
guint n_items;
|
||||
gpointer item;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST (self));
|
||||
|
||||
n_items = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, gtk_string_object_new (string));
|
||||
n_items = self->items->len;
|
||||
item = MAKE_STRING (g_strdup (string));
|
||||
g_ptr_array_add (self->items, item);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), n_items, 0, 1);
|
||||
}
|
||||
@@ -547,11 +607,13 @@ gtk_string_list_take (GtkStringList *self,
|
||||
char *string)
|
||||
{
|
||||
guint n_items;
|
||||
gpointer item;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST (self));
|
||||
|
||||
n_items = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, gtk_string_object_new_take (string));
|
||||
n_items = self->items->len;
|
||||
item = MAKE_STRING (string);
|
||||
g_ptr_array_add (self->items, item);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), n_items, 0, 1);
|
||||
}
|
||||
@@ -568,14 +630,13 @@ void
|
||||
gtk_string_list_remove (GtkStringList *self,
|
||||
guint position)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST (self));
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
g_return_if_fail (!g_sequence_iter_is_end (iter));
|
||||
if (position >= self->items->len)
|
||||
return;
|
||||
|
||||
g_sequence_remove (iter);
|
||||
g_ptr_array_remove_index (self->items, position);
|
||||
gtk_bitset_slice (self->objects, position, 1, 0);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
|
||||
}
|
||||
@@ -597,20 +658,14 @@ const char *
|
||||
gtk_string_list_get_string (GtkStringList *self,
|
||||
guint position)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
gpointer item;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_STRING_LIST (self), NULL);
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
item = g_ptr_array_index (self->items, position);
|
||||
|
||||
if (g_sequence_iter_is_end (iter))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (IS_STRING (item))
|
||||
return (const char *)TO_STRING (item);
|
||||
else
|
||||
{
|
||||
GtkStringObject *obj = g_sequence_get (iter);
|
||||
|
||||
return obj->string;
|
||||
}
|
||||
return GTK_STRING_OBJECT (item)->string;
|
||||
}
|
||||
|
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifndef GTK_VECTOR_TYPE_NAME
|
||||
#define GTK_VECTOR_TYPE_NAME GtkVector
|
||||
#endif
|
||||
|
||||
#ifndef GTK_VECTOR_NAME
|
||||
#define GTK_VECTOR_NAME gtk_vector
|
||||
#endif
|
||||
|
||||
#ifndef GTK_VECTOR_ELEMENT_TYPE
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#endif
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
#if GTK_VECTOR_PREALLOC == 0
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
#define GTK_VECTOR_REAL_SIZE(_size) ((_size) + 1)
|
||||
#else
|
||||
#define GTK_VECTOR_REAL_SIZE(_size) (_size)
|
||||
#endif
|
||||
|
||||
/* make this readable */
|
||||
#define _T_ GTK_VECTOR_ELEMENT_TYPE
|
||||
#define GtkVector GTK_VECTOR_TYPE_NAME
|
||||
#define gtk_vector_paste_more(GTK_VECTOR_NAME, func_name) GTK_VECTOR_NAME ## _ ## func_name
|
||||
#define gtk_vector_paste(GTK_VECTOR_NAME, func_name) gtk_vector_paste_more (GTK_VECTOR_NAME, func_name)
|
||||
#define gtk_vector(func_name) gtk_vector_paste (GTK_VECTOR_NAME, func_name)
|
||||
|
||||
typedef struct GtkVector GtkVector;
|
||||
|
||||
struct GtkVector
|
||||
{
|
||||
_T_ *start;
|
||||
_T_ *end;
|
||||
_T_ *end_allocation;
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
_T_ preallocated[GTK_VECTOR_REAL_SIZE(GTK_VECTOR_PREALLOC)];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */
|
||||
static inline void
|
||||
gtk_vector(init) (GtkVector *self)
|
||||
{
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
self->start = self->preallocated;
|
||||
self->end = self->start;
|
||||
self->end_allocation = self->start + GTK_VECTOR_PREALLOC;
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
*self->start = *(_T_[1]) {};
|
||||
#endif
|
||||
#else
|
||||
self->start = NULL;
|
||||
self->end = NULL;
|
||||
self->end_allocation = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_vector(free_elements) (_T_ *start,
|
||||
_T_ *end)
|
||||
{
|
||||
#ifdef GTK_VECTOR_FREE_FUNC
|
||||
_T_ *e;
|
||||
for (e = start; e < end; e++)
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
GTK_VECTOR_FREE_FUNC (e);
|
||||
#else
|
||||
GTK_VECTOR_FREE_FUNC (*e);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* no G_GNUC_UNUSED here */
|
||||
static inline void
|
||||
gtk_vector(clear) (GtkVector *self)
|
||||
{
|
||||
gtk_vector(free_elements) (self->start, self->end);
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
if (self->start != self->preallocated)
|
||||
g_free (self->start);
|
||||
#endif
|
||||
gtk_vector(init) (self);
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gtk_vector(get_data) (const GtkVector *self)
|
||||
{
|
||||
return self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gtk_vector(index) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return self->start + pos;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gtk_vector(get_capacity) (const GtkVector *self)
|
||||
{
|
||||
return self->end_allocation - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gtk_vector(get_size) (const GtkVector *self)
|
||||
{
|
||||
return self->end - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gboolean
|
||||
gtk_vector(is_empty) (const GtkVector *self)
|
||||
{
|
||||
return self->end == self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(reserve) (GtkVector *self,
|
||||
gsize n)
|
||||
{
|
||||
gsize new_size, size;
|
||||
|
||||
if (n <= gtk_vector(get_capacity) (self))
|
||||
return;
|
||||
|
||||
size = gtk_vector(get_size) (self);
|
||||
new_size = 1 << g_bit_storage (MAX (n, 16) - 1);
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
if (self->start == self->preallocated)
|
||||
{
|
||||
self->start = g_new (_T_, new_size);
|
||||
memcpy (self->start, self->preallocated, sizeof (_T_) * GTK_VECTOR_REAL_SIZE (size));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
if (self->start == NULL)
|
||||
{
|
||||
self->start = g_new (_T_, new_size);
|
||||
*self->start = *(_T_[1]) {};
|
||||
}
|
||||
else
|
||||
#endif
|
||||
self->start = g_renew (_T_, self->start, new_size);
|
||||
|
||||
self->end = self->start + size;
|
||||
self->end_allocation = self->start + new_size;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(splice) (GtkVector *self,
|
||||
gsize pos,
|
||||
gsize removed,
|
||||
_T_ *additions,
|
||||
gsize added)
|
||||
{
|
||||
gsize size;
|
||||
gsize remaining;
|
||||
|
||||
size = gtk_vector(get_size) (self);
|
||||
g_assert (pos + removed <= size);
|
||||
remaining = size - pos - removed;
|
||||
|
||||
gtk_vector(free_elements) (gtk_vector(index) (self, pos),
|
||||
gtk_vector(index) (self, pos + removed));
|
||||
|
||||
gtk_vector(reserve) (self, size - removed + added);
|
||||
|
||||
if (GTK_VECTOR_REAL_SIZE (remaining) && removed != added)
|
||||
memmove (gtk_vector(index) (self, pos + added),
|
||||
gtk_vector(index) (self, pos + removed),
|
||||
GTK_VECTOR_REAL_SIZE (remaining) * sizeof (_T_));
|
||||
|
||||
if (added)
|
||||
{
|
||||
if (additions)
|
||||
memcpy (gtk_vector(index) (self, pos),
|
||||
additions,
|
||||
added * sizeof (_T_));
|
||||
else
|
||||
memset (gtk_vector(index) (self, pos), 0, added * sizeof (_T_));
|
||||
}
|
||||
|
||||
/* might overflow, but does the right thing */
|
||||
self->end += added - removed;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(set_size) (GtkVector *self,
|
||||
gsize new_size)
|
||||
{
|
||||
gsize old_size = gtk_vector(get_size) (self);
|
||||
if (new_size > old_size)
|
||||
gtk_vector(splice) (self, old_size, 0, NULL, new_size - old_size);
|
||||
else
|
||||
gtk_vector(splice) (self, old_size, old_size - new_size, NULL, 0);
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(append) (GtkVector *self,
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
_T_ *value)
|
||||
#else
|
||||
_T_ value)
|
||||
#endif
|
||||
{
|
||||
gtk_vector(splice) (self,
|
||||
gtk_vector(get_size) (self),
|
||||
0,
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
value,
|
||||
#else
|
||||
&value,
|
||||
#endif
|
||||
1);
|
||||
}
|
||||
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
G_GNUC_UNUSED static _T_ *
|
||||
gtk_vector(get) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return gtk_vector(index) (self, pos);
|
||||
}
|
||||
#else
|
||||
G_GNUC_UNUSED static _T_
|
||||
gtk_vector(get) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return *gtk_vector(index) (self, pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GTK_VECTOR_NO_UNDEF
|
||||
|
||||
#undef _T_
|
||||
#undef GtkVector
|
||||
#undef gtk_vector_paste_more
|
||||
#undef gtk_vector_paste
|
||||
#undef gtk_vector
|
||||
#undef GTK_VECTOR_REAL_SIZE
|
||||
|
||||
#undef GTK_VECTOR_BY_VALUE
|
||||
#undef GTK_VECTOR_ELEMENT_TYPE
|
||||
#undef GTK_VECTOR_FREE_FUNC
|
||||
#undef GTK_VECTOR_NAME
|
||||
#undef GTK_VECTOR_NULL_TERMINATED
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
#undef GTK_VECTOR_TYPE_NAME
|
||||
|
||||
#endif
|
@@ -160,7 +160,6 @@ gtk_public_sources = files([
|
||||
'gtkappchooserwidget.c',
|
||||
'gtkapplication.c',
|
||||
'gtkapplicationwindow.c',
|
||||
'gtkarraystore.c',
|
||||
'gtkaspectframe.c',
|
||||
'gtkassistant.c',
|
||||
'gtkbinlayout.c',
|
||||
@@ -448,7 +447,6 @@ gtk_public_headers = files([
|
||||
'gtkappchooserwidget.h',
|
||||
'gtkapplication.h',
|
||||
'gtkapplicationwindow.h',
|
||||
'gtkarraystore.h',
|
||||
'gtkaspectframe.h',
|
||||
'gtkassistant.h',
|
||||
'gtkbinlayout.h',
|
||||
|
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015 Lars Uebernickel
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Lars Uebernickel <lars@uebernic.de>
|
||||
*/
|
||||
|
||||
#include <gtk.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Wrapper around g_list_model_get_item() and g_list_model_get_object() which
|
||||
* checks they return the same thing. */
|
||||
static gpointer
|
||||
list_model_get (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
GObject *item = g_list_model_get_item (model, position);
|
||||
GObject *object = g_list_model_get_object (model, position);
|
||||
|
||||
g_assert_true (item == object);
|
||||
|
||||
g_clear_object (&object);
|
||||
return g_steal_pointer (&item);
|
||||
}
|
||||
|
||||
/* Test that constructing/getting/setting properties on a #GtkArrayStore works. */
|
||||
static void
|
||||
test_store_properties (void)
|
||||
{
|
||||
GtkArrayStore *store = NULL;
|
||||
GType item_type;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_MENU_ITEM);
|
||||
g_object_get (store, "item-type", &item_type, NULL);
|
||||
g_assert_cmpint (item_type, ==, G_TYPE_MENU_ITEM);
|
||||
|
||||
g_clear_object (&store);
|
||||
}
|
||||
|
||||
/* Test that #GtkArrayStore rejects non-GObject item types. */
|
||||
static void
|
||||
test_store_non_gobjects (void)
|
||||
{
|
||||
if (g_test_subprocess ())
|
||||
{
|
||||
/* We have to use g_object_new() since gtk_array_store_new() checks the item
|
||||
* type. We want to check the property setter code works properly. */
|
||||
g_object_new (GTK_TYPE_ARRAY_STORE, "item-type", G_TYPE_LONG, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_test_trap_subprocess (NULL, 0, 0);
|
||||
g_test_trap_assert_failed ();
|
||||
g_test_trap_assert_stderr ("*WARNING*value * of type 'GType' is invalid or "
|
||||
"out of range for property 'item-type'*");
|
||||
}
|
||||
|
||||
#define gtk_array_store_insert(store,position,item) \
|
||||
gtk_array_store_splice (store, position, 0, (gpointer *)&item, 1)
|
||||
|
||||
#define gtk_array_store_remove(store,position) \
|
||||
gtk_array_store_splice (store, position, 1, NULL, 0)
|
||||
|
||||
static void
|
||||
test_store_boundaries (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GMenuItem *item;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_MENU_ITEM);
|
||||
|
||||
item = g_menu_item_new (NULL, NULL);
|
||||
|
||||
/* remove an item from an empty list */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_remove (store, 0);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* don't allow inserting an item past the end ... */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_insert (store, 1, item);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 0);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* ... except exactly at the end */
|
||||
gtk_array_store_insert (store, 0, item);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 1);
|
||||
|
||||
/* remove a non-existing item at exactly the end of the list */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_remove (store, 1);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
gtk_array_store_remove (store, 0);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 0);
|
||||
|
||||
/* splice beyond the end of the list */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_splice (store, 1, 0, NULL, 0);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
/* remove items from an empty list */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_splice (store, 0, 1, NULL, 0);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
gtk_array_store_append (store, item);
|
||||
gtk_array_store_splice (store, 0, 1, (gpointer *) &item, 1);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 1);
|
||||
|
||||
/* remove more items than exist */
|
||||
g_test_expect_message ("Gtk", G_LOG_LEVEL_CRITICAL, "*position*");
|
||||
gtk_array_store_splice (store, 0, 5, NULL, 0);
|
||||
g_test_assert_expected_messages ();
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 1);
|
||||
|
||||
g_object_unref (store);
|
||||
g_assert_finalize_object (item);
|
||||
}
|
||||
|
||||
static void
|
||||
test_store_refcounts (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GMenuItem *items[10];
|
||||
GMenuItem *tmp;
|
||||
guint i;
|
||||
guint n_items;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_MENU_ITEM);
|
||||
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, 0);
|
||||
g_assert_null (list_model_get (G_LIST_MODEL (store), 0));
|
||||
|
||||
n_items = G_N_ELEMENTS (items);
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
items[i] = g_menu_item_new (NULL, NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (items[i]), (gpointer *) &items[i]);
|
||||
gtk_array_store_append (store, items[i]);
|
||||
|
||||
g_object_unref (items[i]);
|
||||
g_assert_nonnull (items[i]);
|
||||
}
|
||||
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, n_items);
|
||||
g_assert_null (list_model_get (G_LIST_MODEL (store), n_items));
|
||||
|
||||
tmp = list_model_get (G_LIST_MODEL (store), 3);
|
||||
g_assert_true (tmp == items[3]);
|
||||
g_object_unref (tmp);
|
||||
|
||||
gtk_array_store_remove (store, 4);
|
||||
g_assert_null (items[4]);
|
||||
n_items--;
|
||||
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (store)), ==, n_items);
|
||||
g_assert_null (list_model_get (G_LIST_MODEL (store), n_items));
|
||||
|
||||
g_object_unref (store);
|
||||
for (i = 0; i < G_N_ELEMENTS (items); i++)
|
||||
g_assert_null (items[i]);
|
||||
}
|
||||
|
||||
/* Test that using splice() to replace the middle element in a list store works. */
|
||||
static void
|
||||
test_store_splice_replace_middle (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GAction *item;
|
||||
GPtrArray *array;
|
||||
|
||||
g_test_bug ("795307");
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
array = g_ptr_array_new_full (0, g_object_unref);
|
||||
g_ptr_array_add (array, g_simple_action_new ("1", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("2", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("3", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("4", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("5", NULL));
|
||||
|
||||
/* Add three items through splice */
|
||||
gtk_array_store_splice (store, 0, 0, array->pdata, 3);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 3);
|
||||
|
||||
item = list_model_get (model, 0);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "1");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 1);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "2");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 2);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "3");
|
||||
g_object_unref (item);
|
||||
|
||||
/* Replace the middle one with two new items */
|
||||
gtk_array_store_splice (store, 1, 1, array->pdata + 3, 2);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 4);
|
||||
|
||||
item = list_model_get (model, 0);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "1");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 1);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "4");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 2);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "5");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 3);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "3");
|
||||
g_object_unref (item);
|
||||
|
||||
g_ptr_array_unref (array);
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that using splice() to replace the whole list store works. */
|
||||
static void
|
||||
test_store_splice_replace_all (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GPtrArray *array;
|
||||
GAction *item;
|
||||
|
||||
g_test_bug ("795307");
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
array = g_ptr_array_new_full (0, g_object_unref);
|
||||
g_ptr_array_add (array, g_simple_action_new ("1", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("2", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("3", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("4", NULL));
|
||||
|
||||
/* Add the first two */
|
||||
gtk_array_store_splice (store, 0, 0, array->pdata, 2);
|
||||
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2);
|
||||
item = list_model_get (model, 0);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "1");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 1);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "2");
|
||||
g_object_unref (item);
|
||||
|
||||
/* Replace all with the last two */
|
||||
gtk_array_store_splice (store, 0, 2, array->pdata + 2, 2);
|
||||
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2);
|
||||
item = list_model_get (model, 0);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "3");
|
||||
g_object_unref (item);
|
||||
item = list_model_get (model, 1);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "4");
|
||||
g_object_unref (item);
|
||||
|
||||
g_ptr_array_unref (array);
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that using splice() without removing or adding anything works */
|
||||
static void
|
||||
test_store_splice_noop (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GAction *item;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
/* splice noop with an empty list */
|
||||
gtk_array_store_splice (store, 0, 0, NULL, 0);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0);
|
||||
|
||||
/* splice noop with a non-empty list */
|
||||
item = G_ACTION (g_simple_action_new ("1", NULL));
|
||||
gtk_array_store_append (store, item);
|
||||
g_object_unref (item);
|
||||
|
||||
gtk_array_store_splice (store, 0, 0, NULL, 0);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1);
|
||||
|
||||
gtk_array_store_splice (store, 1, 0, NULL, 0);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1);
|
||||
|
||||
item = list_model_get (model, 0);
|
||||
g_assert_cmpstr (g_action_get_name (item), ==, "1");
|
||||
g_object_unref (item);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
model_array_equal (GListModel *model, GPtrArray *array)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (g_list_model_get_n_items (model) != array->len)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < array->len; i++)
|
||||
{
|
||||
GObject *ptr;
|
||||
gboolean ptrs_equal;
|
||||
|
||||
ptr = list_model_get (model, i);
|
||||
ptrs_equal = (g_ptr_array_index (array, i) == ptr);
|
||||
g_object_unref (ptr);
|
||||
if (!ptrs_equal)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Test that using splice() to remove multiple items at different
|
||||
* positions works */
|
||||
static void
|
||||
test_store_splice_remove_multiple (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GPtrArray *array;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
array = g_ptr_array_new_full (0, g_object_unref);
|
||||
g_ptr_array_add (array, g_simple_action_new ("1", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("2", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("3", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("4", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("5", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("6", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("7", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("8", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("9", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("10", NULL));
|
||||
|
||||
/* Add all */
|
||||
gtk_array_store_splice (store, 0, 0, array->pdata, array->len);
|
||||
g_assert_true (model_array_equal (model, array));
|
||||
|
||||
/* Remove the first two */
|
||||
gtk_array_store_splice (store, 0, 2, NULL, 0);
|
||||
g_assert_false (model_array_equal (model, array));
|
||||
g_ptr_array_remove_range (array, 0, 2);
|
||||
g_assert_true (model_array_equal (model, array));
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 8);
|
||||
|
||||
/* Remove two in the middle */
|
||||
gtk_array_store_splice (store, 2, 2, NULL, 0);
|
||||
g_assert_false (model_array_equal (model, array));
|
||||
g_ptr_array_remove_range (array, 2, 2);
|
||||
g_assert_true (model_array_equal (model, array));
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 6);
|
||||
|
||||
/* Remove two at the end */
|
||||
gtk_array_store_splice (store, 4, 2, NULL, 0);
|
||||
g_assert_false (model_array_equal (model, array));
|
||||
g_ptr_array_remove_range (array, 4, 2);
|
||||
g_assert_true (model_array_equal (model, array));
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 4);
|
||||
|
||||
g_ptr_array_unref (array);
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that using splice() to add multiple items at different
|
||||
* positions works */
|
||||
static void
|
||||
test_store_splice_add_multiple (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GPtrArray *array;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
array = g_ptr_array_new_full (0, g_object_unref);
|
||||
g_ptr_array_add (array, g_simple_action_new ("1", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("2", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("3", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("4", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("5", NULL));
|
||||
g_ptr_array_add (array, g_simple_action_new ("6", NULL));
|
||||
|
||||
/* Add two at the beginning */
|
||||
gtk_array_store_splice (store, 0, 0, array->pdata, 2);
|
||||
|
||||
/* Add two at the end */
|
||||
gtk_array_store_splice (store, 2, 0, array->pdata + 4, 2);
|
||||
|
||||
/* Add two in the middle */
|
||||
gtk_array_store_splice (store, 2, 0, array->pdata + 2, 2);
|
||||
|
||||
g_assert_true (model_array_equal (model, array));
|
||||
|
||||
g_ptr_array_unref (array);
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that get_item_type() returns the right type */
|
||||
static void
|
||||
test_store_item_type (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GType gtype;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
gtype = g_list_model_get_item_type (G_LIST_MODEL (store));
|
||||
g_assert (gtype == G_TYPE_SIMPLE_ACTION);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that remove_all() removes all items */
|
||||
static void
|
||||
test_store_remove_all (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GSimpleAction *item;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
/* Test with an empty list */
|
||||
gtk_array_store_remove_all (store);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0);
|
||||
|
||||
/* Test with a non-empty list */
|
||||
item = g_simple_action_new ("42", NULL);
|
||||
gtk_array_store_append (store, item);
|
||||
gtk_array_store_append (store, item);
|
||||
g_object_unref (item);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2);
|
||||
gtk_array_store_remove_all (store);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test that splice() logs an error when passed the wrong item type */
|
||||
static void
|
||||
test_store_splice_wrong_type (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
|
||||
g_test_expect_message (G_LOG_DOMAIN,
|
||||
G_LOG_LEVEL_CRITICAL,
|
||||
"*GtkArrayStore instead of a GSimpleAction*");
|
||||
gtk_array_store_splice (store, 0, 0, (gpointer)&store, 1);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Test the cases where the item store tries to speed up item access by caching
|
||||
* the last iter/position */
|
||||
static void
|
||||
test_store_get_item_cache (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GSimpleAction *item1, *item2, *temp;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
/* Add two */
|
||||
item1 = g_simple_action_new ("1", NULL);
|
||||
gtk_array_store_append (store, item1);
|
||||
item2 = g_simple_action_new ("2", NULL);
|
||||
gtk_array_store_append (store, item2);
|
||||
|
||||
/* Clear the cache */
|
||||
g_assert_null (list_model_get (model, 42));
|
||||
|
||||
/* Access the same position twice */
|
||||
temp = list_model_get (model, 1);
|
||||
g_assert (temp == item2);
|
||||
g_object_unref (temp);
|
||||
temp = list_model_get (model, 1);
|
||||
g_assert (temp == item2);
|
||||
g_object_unref (temp);
|
||||
|
||||
g_assert_null (list_model_get (model, 42));
|
||||
|
||||
/* Access forwards */
|
||||
temp = list_model_get (model, 0);
|
||||
g_assert (temp == item1);
|
||||
g_object_unref (temp);
|
||||
temp = list_model_get (model, 1);
|
||||
g_assert (temp == item2);
|
||||
g_object_unref (temp);
|
||||
|
||||
g_assert_null (list_model_get (model, 42));
|
||||
|
||||
/* Access backwards */
|
||||
temp = list_model_get (model, 1);
|
||||
g_assert (temp == item2);
|
||||
g_object_unref (temp);
|
||||
temp = list_model_get (model, 0);
|
||||
g_assert (temp == item1);
|
||||
g_object_unref (temp);
|
||||
|
||||
g_object_unref (item1);
|
||||
g_object_unref (item2);
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
struct ItemsChangedData
|
||||
{
|
||||
guint position;
|
||||
guint removed;
|
||||
guint added;
|
||||
gboolean called;
|
||||
};
|
||||
|
||||
static void
|
||||
expect_items_changed (struct ItemsChangedData *expected,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
expected->position = position;
|
||||
expected->removed = removed;
|
||||
expected->added = added;
|
||||
expected->called = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_items_changed (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
struct ItemsChangedData *expected)
|
||||
{
|
||||
g_assert_false (expected->called);
|
||||
g_assert_cmpuint (expected->position, ==, position);
|
||||
g_assert_cmpuint (expected->removed, ==, removed);
|
||||
g_assert_cmpuint (expected->added, ==, added);
|
||||
expected->called = TRUE;
|
||||
}
|
||||
|
||||
/* Test that all operations on the list emit the items-changed signal */
|
||||
static void
|
||||
test_store_signal_items_changed (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GSimpleAction *item;
|
||||
struct ItemsChangedData expected = {0};
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
g_object_connect (model, "signal::items-changed",
|
||||
on_items_changed, &expected, NULL);
|
||||
|
||||
/* Emit the signal manually */
|
||||
expect_items_changed (&expected, 0, 0, 0);
|
||||
g_list_model_items_changed (model, 0, 0, 0);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
/* Append an item */
|
||||
expect_items_changed (&expected, 0, 0, 1);
|
||||
item = g_simple_action_new ("2", NULL);
|
||||
gtk_array_store_append (store, item);
|
||||
g_object_unref (item);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
/* Insert an item */
|
||||
expect_items_changed (&expected, 1, 0, 1);
|
||||
item = g_simple_action_new ("1", NULL);
|
||||
gtk_array_store_insert (store, 1, item);
|
||||
g_object_unref (item);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
/* Insert an item */
|
||||
expect_items_changed (&expected, 1, 0, 1);
|
||||
item = g_simple_action_new ("3", NULL);
|
||||
gtk_array_store_insert (store, 1, item);
|
||||
g_object_unref (item);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
/* Remove an item */
|
||||
expect_items_changed (&expected, 1, 1, 0);
|
||||
gtk_array_store_remove (store, 1);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
/* Splice */
|
||||
expect_items_changed (&expected, 0, 2, 1);
|
||||
item = g_simple_action_new ("4", NULL);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), >=, 2);
|
||||
gtk_array_store_splice (store, 0, 2, (gpointer)&item, 1);
|
||||
g_object_unref (item);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
g_print ("remove all\n");
|
||||
/* Remove all */
|
||||
expect_items_changed (&expected, 0, 1, 0);
|
||||
g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1);
|
||||
gtk_array_store_remove_all (store);
|
||||
g_assert_true (expected.called);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
/* Due to an overflow in the list store last-iter optimization,
|
||||
* the sequence 'lookup 0; lookup MAXUINT' was returning the
|
||||
* same item twice, and not NULL for the second lookup.
|
||||
* See #1639.
|
||||
*/
|
||||
static void
|
||||
test_store_past_end (void)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
GListModel *model;
|
||||
GSimpleAction *item;
|
||||
|
||||
store = gtk_array_store_new (G_TYPE_SIMPLE_ACTION);
|
||||
model = G_LIST_MODEL (store);
|
||||
|
||||
item = g_simple_action_new ("2", NULL);
|
||||
gtk_array_store_append (store, item);
|
||||
g_object_unref (item);
|
||||
|
||||
g_assert_cmpint (g_list_model_get_n_items (model), ==, 1);
|
||||
item = g_list_model_get_item (model, 0);
|
||||
g_assert_nonnull (item);
|
||||
g_object_unref (item);
|
||||
item = g_list_model_get_item (model, G_MAXUINT);
|
||||
g_assert_null (item);
|
||||
|
||||
g_object_unref (store);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_bug_base ("https://bugzilla.gnome.org/");
|
||||
|
||||
g_test_add_func ("/arraystore/properties", test_store_properties);
|
||||
g_test_add_func ("/arraystore/non-gobjects", test_store_non_gobjects);
|
||||
g_test_add_func ("/arraystore/boundaries", test_store_boundaries);
|
||||
g_test_add_func ("/arraystore/refcounts", test_store_refcounts);
|
||||
g_test_add_func ("/arraystore/splice-replace-middle", test_store_splice_replace_middle);
|
||||
g_test_add_func ("/arraystore/splice-replace-all", test_store_splice_replace_all);
|
||||
g_test_add_func ("/arraystore/splice-noop", test_store_splice_noop);
|
||||
g_test_add_func ("/arraystore/splice-remove-multiple", test_store_splice_remove_multiple);
|
||||
g_test_add_func ("/arraystore/splice-add-multiple", test_store_splice_add_multiple);
|
||||
g_test_add_func ("/arraystore/splice-wrong-type", test_store_splice_wrong_type);
|
||||
g_test_add_func ("/arraystore/item-type", test_store_item_type);
|
||||
g_test_add_func ("/arraystore/remove-all", test_store_remove_all);
|
||||
g_test_add_func ("/arraystore/get-item-cache", test_store_get_item_cache);
|
||||
g_test_add_func ("/arraystore/items-changed", test_store_signal_items_changed);
|
||||
g_test_add_func ("/arraystore/past-end", test_store_past_end);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk.h>
|
||||
#include "gtkstringlist.h"
|
||||
|
||||
struct _GtkStringList2
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GSequence *items;
|
||||
};
|
||||
|
||||
struct _GtkStringList2Class
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GType
|
||||
gtk_string_list2_get_item_type (GListModel *list)
|
||||
{
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_string_list2_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkStringList2 *self = GTK_STRING_LIST2 (list);
|
||||
|
||||
return g_sequence_get_length (self->items);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_string_list2_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkStringList2 *self = GTK_STRING_LIST2 (list);
|
||||
GSequenceIter *iter;
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
|
||||
if (g_sequence_iter_is_end (iter))
|
||||
return NULL;
|
||||
else
|
||||
return g_object_ref (g_sequence_get (iter));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_list2_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_string_list2_get_item_type;
|
||||
iface->get_n_items = gtk_string_list2_get_n_items;
|
||||
iface->get_item = gtk_string_list2_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkStringList2, gtk_string_list2, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||
gtk_string_list2_model_init))
|
||||
|
||||
static void
|
||||
gtk_string_list2_dispose (GObject *object)
|
||||
{
|
||||
GtkStringList2 *self = GTK_STRING_LIST2 (object);
|
||||
|
||||
g_clear_pointer (&self->items, g_sequence_free);
|
||||
|
||||
G_OBJECT_CLASS (gtk_string_list2_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_list2_class_init (GtkStringList2Class *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->dispose = gtk_string_list2_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_string_list2_init (GtkStringList2 *self)
|
||||
{
|
||||
self->items = g_sequence_new (g_object_unref);
|
||||
}
|
||||
|
||||
GtkStringList2 *
|
||||
gtk_string_list2_new (const char * const *strings)
|
||||
{
|
||||
GtkStringList2 *self;
|
||||
|
||||
self = g_object_new (GTK_TYPE_STRING_LIST2, NULL);
|
||||
|
||||
gtk_string_list2_splice (self, 0, 0, strings);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GObject obj;
|
||||
char *str;
|
||||
} StrObj;
|
||||
|
||||
static GtkStringObject *
|
||||
string_object_new (const char *string)
|
||||
{
|
||||
GtkStringObject *s;
|
||||
|
||||
s = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
|
||||
((StrObj*)s)->str = g_strdup (string);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_string_list2_splice (GtkStringList2 *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char * const *additions)
|
||||
{
|
||||
guint n_items;
|
||||
guint add;
|
||||
GSequenceIter *it;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST2 (self));
|
||||
g_return_if_fail (position + n_removals >= position); /* overflow */
|
||||
|
||||
n_items = g_sequence_get_length (self->items);
|
||||
g_return_if_fail (position + n_removals <= n_items);
|
||||
|
||||
it = g_sequence_get_iter_at_pos (self->items, position);
|
||||
|
||||
if (n_removals)
|
||||
{
|
||||
GSequenceIter *end;
|
||||
|
||||
end = g_sequence_iter_move (it, n_removals);
|
||||
g_sequence_remove_range (it, end);
|
||||
|
||||
it = end;
|
||||
}
|
||||
|
||||
if (additions)
|
||||
{
|
||||
for (add = 0; additions[add]; add++)
|
||||
{
|
||||
g_sequence_insert_before (it, string_object_new (additions[add]));
|
||||
}
|
||||
}
|
||||
else
|
||||
add = 0;
|
||||
|
||||
if (n_removals || add)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, add);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_string_list2_append (GtkStringList2 *self,
|
||||
const char *string)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST2 (self));
|
||||
|
||||
n_items = g_sequence_get_length (self->items);
|
||||
g_sequence_append (self->items, string_object_new (string));
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), n_items, 0, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_string_list2_remove (GtkStringList2 *self,
|
||||
guint position)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST2 (self));
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
g_return_if_fail (!g_sequence_iter_is_end (iter));
|
||||
|
||||
g_sequence_remove (iter);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
|
||||
}
|
||||
|
||||
const char *
|
||||
gtk_string_list2_get_string (GtkStringList2 *self,
|
||||
guint position)
|
||||
{
|
||||
GSequenceIter *iter;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_STRING_LIST (self), NULL);
|
||||
|
||||
iter = g_sequence_get_iter_at_pos (self->items, position);
|
||||
|
||||
if (g_sequence_iter_is_end (iter))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkStringObject *obj = g_sequence_get (iter);
|
||||
|
||||
return gtk_string_object_get_string (obj);
|
||||
}
|
||||
}
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_STRING_LIST2_H__
|
||||
#define __GTK_STRING_LIST2_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
/* for GDK_AVAILABLE_IN_ALL */
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_STRING_LIST2 (gtk_string_list2_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkStringList2, gtk_string_list2, GTK, STRING_LIST2, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkStringList2 * gtk_string_list2_new (const char * const *strings);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list2_append (GtkStringList2 *self,
|
||||
const char *string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list2_take (GtkStringList2 *self,
|
||||
char *string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list2_remove (GtkStringList2 *self,
|
||||
guint position);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list2_splice (GtkStringList2 *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char * const *additions);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_string_list2_get_string (GtkStringList2 *self,
|
||||
guint position);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_STRING_LIST2_H__ */
|
@@ -1,25 +1,20 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gtkstringlist.h"
|
||||
|
||||
typedef struct {
|
||||
GObject obj;
|
||||
char *str;
|
||||
} StrObj;
|
||||
|
||||
static GtkStringObject *
|
||||
static GObject *
|
||||
get_object (const char *string)
|
||||
{
|
||||
GtkStringObject *s;
|
||||
GtkStringList *list;
|
||||
GObject *obj;
|
||||
|
||||
s = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
|
||||
((StrObj*)s)->str = g_strdup (string);
|
||||
list = gtk_string_list_new ((const char *[]){string, NULL});
|
||||
obj = g_list_model_get_item (G_LIST_MODEL (list), 0);
|
||||
g_object_unref (list);
|
||||
|
||||
return s;
|
||||
return obj;
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
make_list_store (guint n_items)
|
||||
make_store (guint n_items)
|
||||
{
|
||||
GListStore *store;
|
||||
guint i;
|
||||
@@ -29,7 +24,7 @@ make_list_store (guint n_items)
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
char *string;
|
||||
gpointer obj;
|
||||
GObject *obj;
|
||||
|
||||
string = g_strdup_printf ("item %d", i);
|
||||
obj = get_object (string);
|
||||
@@ -41,72 +36,8 @@ make_list_store (guint n_items)
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
make_array_store (guint n_items)
|
||||
{
|
||||
GtkArrayStore *store;
|
||||
guint i;
|
||||
|
||||
store = gtk_array_store_new (GTK_TYPE_STRING_OBJECT);
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
char *string;
|
||||
gpointer obj;
|
||||
|
||||
string = g_strdup_printf ("item %d", i);
|
||||
obj = get_object (string);
|
||||
gtk_array_store_append (store, obj);
|
||||
g_object_unref (obj);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
make_string_list2 (guint n_items)
|
||||
{
|
||||
GtkStringList2 *store;
|
||||
guint i;
|
||||
|
||||
store = gtk_string_list2_new (NULL);
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
char *string;
|
||||
|
||||
string = g_strdup_printf ("item %d", i);
|
||||
gtk_string_list2_append (store, string);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
make_string_list (guint n_items)
|
||||
{
|
||||
GtkStringList *store;
|
||||
guint i;
|
||||
|
||||
store = gtk_string_list_new (NULL);
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
char *string;
|
||||
|
||||
string = g_strdup_printf ("item %d", i);
|
||||
gtk_string_list_append (store, string);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_access (const char *kind,
|
||||
guint size)
|
||||
do_random_access (guint size)
|
||||
{
|
||||
GListModel *model;
|
||||
guint i;
|
||||
@@ -115,16 +46,7 @@ do_random_access (const char *kind,
|
||||
gint64 start, end;
|
||||
guint iterations = 10000000;
|
||||
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
model = make_list_store (size);
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
model = make_array_store (size);
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
model = make_string_list2 (size);
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
model = make_string_list (size);
|
||||
else
|
||||
g_error ("unsupported: %s", kind);
|
||||
model = make_store (size);
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
@@ -139,232 +61,23 @@ do_random_access (const char *kind,
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
g_print ("\"random access\",\"%s\", %u, %g\n",
|
||||
kind,
|
||||
g_print ("size %u: %g accesses per second\n",
|
||||
size,
|
||||
((double)(end - start)) / iterations);
|
||||
(iterations / (double) G_TIME_SPAN_SECOND) * ((double)(end - start)));
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
static void
|
||||
do_linear_access (const char *kind,
|
||||
guint size)
|
||||
{
|
||||
GListModel *model;
|
||||
guint i;
|
||||
GtkStringObject *obj;
|
||||
gint64 start, end;
|
||||
guint iterations = 10000000;
|
||||
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
model = make_list_store (size);
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
model = make_array_store (size);
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
model = make_string_list2 (size);
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
model = make_string_list (size);
|
||||
else
|
||||
g_error ("unsupported: %s", kind);
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
obj = g_list_model_get_item (model, i % size);
|
||||
if (g_getenv ("PRINT_ACCESS"))
|
||||
g_print ("%s", gtk_string_object_get_string (obj));
|
||||
g_object_unref (obj);
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
g_print ("\"linear access\", \"%s\", %u, %g\n",
|
||||
kind,
|
||||
size,
|
||||
((double)(end - start)) / iterations);
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
static void
|
||||
do_append (const char *kind,
|
||||
guint size)
|
||||
{
|
||||
GListModel *model;
|
||||
guint i, j;
|
||||
gint64 start, end;
|
||||
int iterations = 5;
|
||||
gint64 total;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
model = make_list_store (0);
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
model = make_array_store (0);
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
model = make_string_list2 (0);
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
model = make_string_list (0);
|
||||
else
|
||||
g_error ("unsupported: %s", kind);
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (j = 0; j < size; j++)
|
||||
{
|
||||
char *string = g_strdup_printf ("item %d", j);
|
||||
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
{
|
||||
gpointer obj = get_object (string);
|
||||
g_list_store_append (G_LIST_STORE (model), obj);
|
||||
g_object_unref (obj);
|
||||
}
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
{
|
||||
gpointer obj = get_object (string);
|
||||
gtk_array_store_append (GTK_ARRAY_STORE (model), obj);
|
||||
g_object_unref (obj);
|
||||
}
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
gtk_string_list2_append (GTK_STRING_LIST2 (model), string);
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
gtk_string_list_append (GTK_STRING_LIST (model), string);
|
||||
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
total += end - start;
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
g_print ("\"append\", \"%s\", %u, %g\n", kind, size, ((double)total) / iterations);
|
||||
}
|
||||
|
||||
#define gtk_array_store_insert(store,position,item) \
|
||||
gtk_array_store_splice (store, position, 0, (gpointer *)&item, 1)
|
||||
|
||||
static void
|
||||
do_insert (const char *kind,
|
||||
guint size)
|
||||
{
|
||||
GListModel *model;
|
||||
guint i, j;
|
||||
gint64 start, end;
|
||||
int iterations = 5;
|
||||
gint64 total;
|
||||
guint position;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
model = make_list_store (1);
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
model = make_array_store (1);
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
model = make_string_list2 (1);
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
model = make_string_list (1);
|
||||
else
|
||||
g_error ("unsupported: %s", kind);
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (j = 1; j < size; j++)
|
||||
{
|
||||
char *string = g_strdup_printf ("item %d", j);
|
||||
position = g_random_int_range (0, j);
|
||||
|
||||
if (strcmp (kind, "liststore") == 0)
|
||||
{
|
||||
gpointer obj = get_object (string);
|
||||
g_list_store_insert (G_LIST_STORE (model), position, obj);
|
||||
g_object_unref (obj);
|
||||
}
|
||||
else if (strcmp (kind, "arraystore") == 0)
|
||||
{
|
||||
gpointer obj = get_object (string);
|
||||
gtk_array_store_insert (GTK_ARRAY_STORE (model), position, obj);
|
||||
g_object_unref (obj);
|
||||
}
|
||||
else if (strcmp (kind, "stringlist") == 0)
|
||||
gtk_string_list2_splice (GTK_STRING_LIST2 (model), position, 0,
|
||||
(const char * const []){string, NULL});
|
||||
else if (strcmp (kind, "array stringlist") == 0)
|
||||
gtk_string_list_splice (GTK_STRING_LIST (model), position, 0,
|
||||
(const char * const []){string, NULL});
|
||||
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
total += end - start;
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
g_print ("\"insert\", \"%s\", %u, %g\n", kind, size, ((double)total) / iterations);
|
||||
}
|
||||
|
||||
static void
|
||||
random_access (void)
|
||||
{
|
||||
const char *kind[] = { "liststore", "arraystore", "stringlist", "array stringlist" };
|
||||
int sizes = 22;
|
||||
int size;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (kind); i++)
|
||||
for (j = 0, size = 2; j < sizes; j++, size *= 2)
|
||||
do_random_access (kind[i], size);
|
||||
}
|
||||
|
||||
static void
|
||||
linear_access (void)
|
||||
{
|
||||
const char *kind[] = { "liststore", "arraystore", "stringlist", "array stringlist" };
|
||||
int sizes = 22;
|
||||
int size;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (kind); i++)
|
||||
for (j = 0, size = 2; j < sizes; j++, size *= 2)
|
||||
do_linear_access (kind[i], size);
|
||||
}
|
||||
|
||||
static void
|
||||
append (void)
|
||||
{
|
||||
const char *kind[] = { "liststore", "arraystore", "stringlist", "array stringlist" };
|
||||
int sizes = 22;
|
||||
int size;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (kind); i++)
|
||||
for (j = 0, size = 2; j < sizes; j++, size *= 2)
|
||||
do_append (kind[i], size);
|
||||
}
|
||||
|
||||
static void
|
||||
insert (void)
|
||||
{
|
||||
const char *kind[] = { "liststore", "arraystore", "stringlist", "array stringlist" };
|
||||
int sizes = 22;
|
||||
int size;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (kind); i++)
|
||||
for (j = 0, size = 2; j < sizes; j++, size *= 2)
|
||||
do_insert (kind[i], size);
|
||||
do_random_access (1e1);
|
||||
do_random_access (1e2);
|
||||
do_random_access (1e3);
|
||||
do_random_access (1e4);
|
||||
do_random_access (1e5);
|
||||
do_random_access (1e6);
|
||||
do_random_access (1e7);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -372,11 +85,7 @@ main (int argc, char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
g_print ("\"test\",\"model\",\"model size\",\"time\"");
|
||||
g_test_add_func ("/model/random-access", random_access);
|
||||
g_test_add_func ("/model/linear-access", linear_access);
|
||||
g_test_add_func ("/model/append", append);
|
||||
g_test_add_func ("/model/insert", insert);
|
||||
g_test_add_func ("/liststore/random-access", random_access);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ tests = [
|
||||
['accessible'],
|
||||
['action'],
|
||||
['adjustment'],
|
||||
['arraystore'],
|
||||
['bitset'],
|
||||
['bitmask', ['../../gtk/gtkallocatedbitmask.c'], ['-DGTK_COMPILATION', '-UG_ENABLE_DEBUG']],
|
||||
['builder', [], [], gtk_tests_export_dynamic_ldflag],
|
||||
@@ -75,10 +74,9 @@ tests = [
|
||||
['typename'],
|
||||
['displayclose'],
|
||||
['revealer-size'],
|
||||
['vector'],
|
||||
['widgetorder'],
|
||||
['widget-refcount'],
|
||||
['listmodel-performance', ['listmodel-performance.c','gtkstringlist.c']]
|
||||
['listmodel-performance'],
|
||||
]
|
||||
|
||||
# Tests that are expected to fail
|
||||
|
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
int_free_func (int data)
|
||||
{
|
||||
}
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME IntVector
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME pre_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME PreIntVector
|
||||
#define GTK_VECTOR_PREALLOC 100
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME free_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME FreeIntVector
|
||||
#define GTK_VECTOR_FREE_FUNC int_free_func
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME pre_free_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME PreFreeIntVector
|
||||
#define GTK_VECTOR_PREALLOC 100
|
||||
#define GTK_VECTOR_FREE_FUNC int_free_func
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME null_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME NullIntVector
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME null_pre_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME NullPreIntVector
|
||||
#define GTK_VECTOR_PREALLOC 100
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME null_free_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME NullFreeIntVector
|
||||
#define GTK_VECTOR_FREE_FUNC int_free_func
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#include "vectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE int
|
||||
#define GTK_VECTOR_NAME null_pre_free_int_vector
|
||||
#define GTK_VECTOR_TYPE_NAME NullPreFreeIntVector
|
||||
#define GTK_VECTOR_PREALLOC 100
|
||||
#define GTK_VECTOR_FREE_FUNC int_free_func
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#include "vectorimpl.c"
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
setlocale (LC_ALL, "C");
|
||||
|
||||
g_test_add_func ("/intvector/simple", int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/prealloc/simple", pre_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/freefunc/simple", free_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/prealloc/freefunc/simple", pre_free_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/null/simple", null_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/null/prealloc/simple", null_pre_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/null/freefunc/simple", null_free_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/null/prealloc/freefunc/simple", null_pre_free_int_vector_test_simple);
|
||||
g_test_add_func ("/intvector/splice", int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/prealloc/splice", pre_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/freefunc/splice", free_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/prealloc/freefunc/splice", pre_free_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/null/splice", null_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/null/prealloc/splice", null_pre_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/null/freefunc/splice", null_free_int_vector_test_splice);
|
||||
g_test_add_func ("/intvector/null/prealloc/freefunc/splice", null_pre_free_int_vector_test_splice);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GTK_VECTOR_NO_UNDEF
|
||||
|
||||
#include "../../gtk/gtkvectorimpl.c"
|
||||
|
||||
static void
|
||||
gtk_vector(test_simple) (void)
|
||||
{
|
||||
GtkVector v;
|
||||
gsize i;
|
||||
|
||||
gtk_vector(init) (&v);
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), ==, i);
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), <=, gtk_vector(get_capacity) (&v));
|
||||
gtk_vector(append) (&v, i);
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
g_assert_cmpint (*gtk_vector(index) (&v, gtk_vector(get_size) (&v)), ==, 0);
|
||||
#endif
|
||||
}
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), ==, i);
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), <=, gtk_vector(get_capacity) (&v));
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
g_assert_cmpint (gtk_vector(get) (&v, i), ==, i);
|
||||
}
|
||||
|
||||
gtk_vector(clear) (&v);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_vector(test_splice) (void)
|
||||
{
|
||||
GtkVector v;
|
||||
gsize i, j, sum;
|
||||
gsize pos, add, remove;
|
||||
int additions[4] = { 0, 1, 2, 3 };
|
||||
|
||||
gtk_vector(init) (&v);
|
||||
sum = 0;
|
||||
|
||||
for (i = 0; i < 1000; i++)
|
||||
{
|
||||
gsize old_size = gtk_vector(get_size) (&v);
|
||||
|
||||
pos = g_random_int_range (0, old_size + 1);
|
||||
g_assert (pos <= old_size);
|
||||
remove = g_random_int_range (0, 4);
|
||||
remove = MIN (remove, old_size - pos);
|
||||
add = g_random_int_range (0, 4);
|
||||
|
||||
for (j = 0; j < remove; j++)
|
||||
sum -= gtk_vector(get) (&v, pos + j);
|
||||
for (j = 0; j < add; j++)
|
||||
sum += ++additions[j];
|
||||
|
||||
gtk_vector(splice) (&v, pos, remove, additions, add);
|
||||
{
|
||||
gsize total = 0;
|
||||
for (j = 0; j < gtk_vector(get_size) (&v); j++)
|
||||
total += gtk_vector(get) (&v, j);
|
||||
g_assert_cmpint (total, ==, sum);
|
||||
}
|
||||
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), ==, old_size + add - remove);
|
||||
g_assert_cmpint (gtk_vector(get_size) (&v), <=, gtk_vector(get_capacity) (&v));
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
g_assert_cmpint (*gtk_vector(index) (&v, gtk_vector(get_size) (&v)), ==, 0);
|
||||
#endif
|
||||
for (j = 0; j < add; j++)
|
||||
g_assert_cmpint (gtk_vector(get) (&v, pos + j), ==, additions[j]);
|
||||
}
|
||||
|
||||
for (i = 0; i < gtk_vector(get_size) (&v); i++)
|
||||
{
|
||||
sum -= gtk_vector(get) (&v, i);
|
||||
}
|
||||
g_assert_cmpint (sum, ==, 0);
|
||||
}
|
||||
|
||||
#undef _T_
|
||||
#undef GtkVector
|
||||
#undef gtk_vector_paste_more
|
||||
#undef gtk_vector_paste
|
||||
#undef gtk_vector
|
||||
#undef GTK_VECTOR_REAL_SIZE
|
||||
|
||||
#undef GTK_VECTOR_ELEMENT_TYPE
|
||||
#undef GTK_VECTOR_NAME
|
||||
#undef GTK_VECTOR_TYPE_NAME
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
#undef GTK_VECTOR_NULL_TERMINATED
|
||||
|
Reference in New Issue
Block a user