Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e1d8cac0e | |||
| 7f54cf6294 | |||
| 6e0839a956 | |||
| abd9a19a94 | |||
| 1f0ace7454 | |||
| 802c99d4b4 | |||
| 173534710a | |||
| 347959a112 | |||
| 1ae939cf5a | |||
| edf523fe30 | |||
| bfe2970a98 | |||
| c7749b9098 | |||
| 2226fe0fca | |||
| cbf9375f97 | |||
| 5297eb36b9 | |||
| b69e7777cd | |||
| 817da34f7e | |||
| 8fa44fc3e6 | |||
| c7e94151b2 | |||
| 729ba44297 | |||
| 2a2a6879c5 | |||
| e7b773b031 | |||
| 57a225681c | |||
| ea07a92366 | |||
| 76290e8ddb | |||
| 26d83b1ab7 | |||
| 2bba856206 | |||
| bf3382a89e | |||
| 3162e25671 | |||
| 3d931b4fe2 | |||
| fc770a383a | |||
| 62c385a9dd | |||
| 7c4ad1a5c4 | |||
| ac524bb13a | |||
| 66fa9380b5 | |||
| b64eb6ca13 | |||
| 9b2d8ac362 | |||
| 2a90bc1a9b | |||
| d4b868d9bc | |||
| b54f6710a7 | |||
| 6bb7caf155 | |||
| 202348f9d0 | |||
| 1a613de2f6 | |||
| 665df37703 | |||
| acad5e4e3d | |||
| 6267c8469b | |||
| 5a2f791bdd | |||
| 286a00a1db | |||
| 11dd602b28 | |||
| 35988d659d | |||
| be3449b3ce | |||
| 2d8fddc1e9 | |||
| 644d522d19 | |||
| a8b0125da1 | |||
| acccac516e | |||
| d65214fa4e | |||
| 1d96fc8237 | |||
| 882a87ca19 | |||
| 1dbb8df95f | |||
| f6c2c2edbd | |||
| c4e4de36f6 | |||
| 67cbb2a7d3 | |||
| a979daa8ea | |||
| fb14f50ec1 | |||
| 6099fbafc1 | |||
| 6f2f828bce | |||
| 795d3122cc | |||
| 5080730728 | |||
| f75a3a0e95 | |||
| b75db7d1c6 | |||
| b03069bdf6 | |||
| 1c71e56e75 | |||
| 9332d0dcc8 | |||
| 9ad37583e6 | |||
| 69975627e9 | |||
| b74a489aba | |||
| 599b807726 | |||
| 6510ca8bdd |
@@ -188,7 +188,7 @@ constraint_view_init (ConstraintView *self)
|
||||
g_list_store_append (list, children);
|
||||
g_list_store_append (list, guides);
|
||||
g_list_store_append (list, constraints);
|
||||
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list)));
|
||||
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
|
||||
g_object_unref (children);
|
||||
g_object_unref (guides);
|
||||
g_object_unref (constraints);
|
||||
|
||||
@@ -226,6 +226,7 @@
|
||||
<file>listview_minesweeper.c</file>
|
||||
<file>listview_settings.c</file>
|
||||
<file>listview_weather.c</file>
|
||||
<file>listview_words.c</file>
|
||||
<file>list_store.c</file>
|
||||
<file>markup.c</file>
|
||||
<file>modelbutton.c</file>
|
||||
|
||||
@@ -676,7 +676,7 @@ create_color_grid (void)
|
||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
|
||||
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
|
||||
|
||||
model = G_LIST_MODEL (gtk_sort_list_model_new (gtk_color_list_new (0), NULL));
|
||||
model = G_LIST_MODEL (gtk_sor3_list_model_new (gtk_color_list_new (0), NULL));
|
||||
|
||||
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
|
||||
@@ -835,6 +835,54 @@ update_selection_average (GListModel *model,
|
||||
g_object_unref (color);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_red (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkColor *colora = (GtkColor *) a;
|
||||
GtkColor *colorb = (GtkColor *) b;
|
||||
|
||||
if (colora->color.red < colorb->color.red)
|
||||
return GTK_ORDERING_LARGER;
|
||||
else if (colora->color.red > colorb->color.red)
|
||||
return GTK_ORDERING_SMALLER;
|
||||
else
|
||||
return GTK_ORDERING_EQUAL;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_green (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkColor *colora = (GtkColor *) a;
|
||||
GtkColor *colorb = (GtkColor *) b;
|
||||
|
||||
if (colora->color.green < colorb->color.green)
|
||||
return GTK_ORDERING_LARGER;
|
||||
else if (colora->color.green > colorb->color.green)
|
||||
return GTK_ORDERING_SMALLER;
|
||||
else
|
||||
return GTK_ORDERING_EQUAL;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_blue (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer unused)
|
||||
{
|
||||
GtkColor *colora = (GtkColor *) a;
|
||||
GtkColor *colorb = (GtkColor *) b;
|
||||
|
||||
if (colora->color.blue < colorb->color.blue)
|
||||
return GTK_ORDERING_LARGER;
|
||||
else if (colora->color.blue > colorb->color.blue)
|
||||
return GTK_ORDERING_SMALLER;
|
||||
else
|
||||
return GTK_ORDERING_EQUAL;
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
@@ -964,7 +1012,7 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
button = gtk_button_new_with_mnemonic ("_Refill");
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (refill),
|
||||
gtk_sort_list_model_get_model (GTK_SORT_LIST_MODEL (model)));
|
||||
gtk_sor3_list_model_get_model (GTK_SOR3_LIST_MODEL (model)));
|
||||
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
||||
|
||||
@@ -987,7 +1035,7 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
gtk_drop_down_set_from_strings (GTK_DROP_DOWN (dropdown), (const char *[]) { "8", "64", "512", "4096", "32768", "262144", "2097152", "16777216", NULL });
|
||||
g_signal_connect (dropdown, "notify::selected",
|
||||
G_CALLBACK (limit_changed_cb),
|
||||
gtk_sort_list_model_get_model (GTK_SORT_LIST_MODEL (model)));
|
||||
gtk_sor3_list_model_get_model (GTK_SOR3_LIST_MODEL (model)));
|
||||
g_signal_connect (dropdown, "notify::selected",
|
||||
G_CALLBACK (limit_changed_cb2),
|
||||
label);
|
||||
@@ -1022,18 +1070,30 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
g_list_store_append (sorters, sorter);
|
||||
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
|
||||
|
||||
sorter = gtk_custom_sorter_new (compare_red, NULL, NULL);
|
||||
set_title (sorter, "Red (fast)");
|
||||
g_list_store_append (sorters, sorter);
|
||||
|
||||
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "green"));
|
||||
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
|
||||
set_title (sorter, "Green");
|
||||
g_list_store_append (sorters, sorter);
|
||||
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
|
||||
|
||||
sorter = gtk_custom_sorter_new (compare_green, NULL, NULL);
|
||||
set_title (sorter, "Green (fast)");
|
||||
g_list_store_append (sorters, sorter);
|
||||
|
||||
sorter = gtk_numeric_sorter_new (gtk_property_expression_new (GTK_TYPE_COLOR, NULL, "blue"));
|
||||
gtk_numeric_sorter_set_sort_order (GTK_NUMERIC_SORTER (sorter), GTK_SORT_DESCENDING);
|
||||
set_title (sorter, "Blue");
|
||||
g_list_store_append (sorters, sorter);
|
||||
gtk_multi_sorter_append (GTK_MULTI_SORTER (multi_sorter), sorter);
|
||||
|
||||
sorter = gtk_custom_sorter_new (compare_blue, NULL, NULL);
|
||||
set_title (sorter, "Blue (fast)");
|
||||
g_list_store_append (sorters, sorter);
|
||||
|
||||
set_title (multi_sorter, "RGB");
|
||||
g_list_store_append (sorters, multi_sorter);
|
||||
g_object_unref (multi_sorter);
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/* Lists/Words
|
||||
*
|
||||
* This demo shows filtering a long list - of words.
|
||||
*
|
||||
* You should have the file `/usr/share/dict/words` installed for
|
||||
* this demo to work.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *progress;
|
||||
|
||||
const char *factory_text =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkLabel'>\n"
|
||||
" <property name='ellipsize'>end</property>\n"
|
||||
" <property name='xalign'>0</property>\n"
|
||||
" <binding name='label'>\n"
|
||||
" <lookup name='string' type='GtkStringObject'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
static void
|
||||
update_title_cb (GtkFilterListModel *model)
|
||||
{
|
||||
guint total;
|
||||
char *title;
|
||||
guint pending;
|
||||
|
||||
total = g_list_model_get_n_items (gtk_filter_list_model_get_model (model));
|
||||
pending = gtk_filter_list_model_get_pending (model);
|
||||
|
||||
title = g_strdup_printf ("%u lines", g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
|
||||
gtk_widget_set_visible (progress, pending != 0);
|
||||
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (total - pending) / (double) total);
|
||||
gtk_window_set_title (GTK_WINDOW (window), title);
|
||||
g_free (title);
|
||||
}
|
||||
|
||||
static void
|
||||
read_lines_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (object);
|
||||
GtkStringList *stringlist = data;
|
||||
GError *error = NULL;
|
||||
gsize size;
|
||||
GPtrArray *lines;
|
||||
gssize n_filled;
|
||||
const char *buffer, *newline;
|
||||
|
||||
n_filled = g_buffered_input_stream_fill_finish (stream, result, &error);
|
||||
if (n_filled < 0)
|
||||
{
|
||||
g_print ("Could not read data: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||
|
||||
if (n_filled == 0)
|
||||
{
|
||||
if (size)
|
||||
gtk_string_list_take (stringlist, g_utf8_make_valid (buffer, size));
|
||||
return;
|
||||
}
|
||||
|
||||
lines = NULL;
|
||||
while ((newline = memchr (buffer, '\n', size)))
|
||||
{
|
||||
if (newline > buffer)
|
||||
{
|
||||
if (lines == NULL)
|
||||
lines = g_ptr_array_new_with_free_func (g_free);
|
||||
g_ptr_array_add (lines, g_utf8_make_valid (buffer, newline - buffer));
|
||||
}
|
||||
if (g_input_stream_skip (G_INPUT_STREAM (stream), newline - buffer + 1, NULL, &error) < 0)
|
||||
{
|
||||
g_clear_error (&error);
|
||||
break;
|
||||
}
|
||||
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||
}
|
||||
if (lines == NULL)
|
||||
{
|
||||
g_buffered_input_stream_set_buffer_size (stream, g_buffered_input_stream_get_buffer_size (stream) + 4096);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (lines, NULL);
|
||||
gtk_string_list_splice (stringlist, g_list_model_get_n_items (G_LIST_MODEL (stringlist)), 0, (const char **) lines->pdata);
|
||||
g_ptr_array_free (lines, TRUE);
|
||||
}
|
||||
|
||||
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||
}
|
||||
|
||||
static void
|
||||
file_is_open_cb (GObject *file,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GFileInputStream *file_stream;
|
||||
GBufferedInputStream *stream;
|
||||
|
||||
file_stream = g_file_read_finish (G_FILE (file), result, &error);
|
||||
if (file_stream == NULL)
|
||||
{
|
||||
g_print ("Could not open file: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
stream = G_BUFFERED_INPUT_STREAM (g_buffered_input_stream_new (G_INPUT_STREAM (file_stream)));
|
||||
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static void
|
||||
load_file (GtkStringList *list,
|
||||
GFile *file)
|
||||
{
|
||||
gtk_string_list_splice (list, 0, g_list_model_get_n_items (G_LIST_MODEL (list)), NULL);
|
||||
g_file_read_async (file, G_PRIORITY_HIGH_IDLE, NULL, file_is_open_cb, list);
|
||||
}
|
||||
|
||||
static void
|
||||
file_selected_cb (GtkWidget *button,
|
||||
GtkStringList *stringlist)
|
||||
{
|
||||
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (button));
|
||||
|
||||
if (file)
|
||||
{
|
||||
load_file (stringlist, file);
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_listview_words (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *header, *listview, *sw, *vbox, *search_entry, *open_button, *overlay;
|
||||
GtkFilterListModel *filter_model;
|
||||
GtkNoSelection *selection;
|
||||
GtkStringList *stringlist;
|
||||
GtkFilter *filter;
|
||||
GtkExpression *expression;
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_path ("/usr/share/dict/words");
|
||||
if (g_file_query_exists (file, NULL))
|
||||
{
|
||||
stringlist = gtk_string_list_new (NULL);
|
||||
load_file (stringlist, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char **words;
|
||||
words = g_strsplit ("lorem ipsum dolor sit amet consectetur adipisci elit sed eiusmod tempor incidunt labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat", " ", -1);
|
||||
stringlist = gtk_string_list_new ((const char **) words);
|
||||
g_strfreev (words);
|
||||
}
|
||||
|
||||
filter = gtk_string_filter_new ();
|
||||
expression = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string");
|
||||
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
|
||||
gtk_expression_unref (expression);
|
||||
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (stringlist), filter);
|
||||
gtk_filter_list_model_set_incremental (filter_model, TRUE);
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
open_button = gtk_file_chooser_button_new ("_Open", GTK_FILE_CHOOSER_ACTION_OPEN);
|
||||
g_signal_connect (open_button, "file-set", G_CALLBACK (file_selected_cb), stringlist);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), open_button);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
||||
|
||||
search_entry = gtk_search_entry_new ();
|
||||
g_object_bind_property (search_entry, "text", filter, "search", 0);
|
||||
gtk_box_append (GTK_BOX (vbox), search_entry);
|
||||
|
||||
overlay = gtk_overlay_new ();
|
||||
gtk_box_append (GTK_BOX (vbox), overlay);
|
||||
|
||||
progress = gtk_progress_bar_new ();
|
||||
gtk_widget_set_halign (progress, GTK_ALIGN_FILL);
|
||||
gtk_widget_set_valign (progress, GTK_ALIGN_START);
|
||||
gtk_widget_set_hexpand (progress, TRUE);
|
||||
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), progress);
|
||||
|
||||
sw = gtk_scrolled_window_new ();
|
||||
gtk_overlay_set_child (GTK_OVERLAY (overlay), sw);
|
||||
|
||||
listview = gtk_list_view_new_with_factory (
|
||||
gtk_builder_list_item_factory_new_from_bytes (NULL,
|
||||
g_bytes_new_static (factory_text, strlen (factory_text))));
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
selection = gtk_no_selection_new (G_LIST_MODEL (filter_model));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
|
||||
g_object_unref (selection);
|
||||
|
||||
g_signal_connect (filter_model, "items-changed", G_CALLBACK (update_title_cb), progress);
|
||||
g_signal_connect (filter_model, "notify::pending", G_CALLBACK (update_title_cb), progress);
|
||||
update_title_cb (filter_model);
|
||||
|
||||
g_object_unref (filter_model);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -49,6 +49,7 @@ demos = files([
|
||||
'listview_minesweeper.c',
|
||||
'listview_settings.c',
|
||||
'listview_weather.c',
|
||||
'listview_words.c',
|
||||
'markup.c',
|
||||
'modelbutton.c',
|
||||
'overlay.c',
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
<section>
|
||||
<xi:include href="xml/gtkfilter.xml" />
|
||||
<xi:include href="xml/gtkcustomfilter.xml" />
|
||||
<xi:include href="xml/gtkstringfilter.xml" />
|
||||
<xi:include href="xml/gtkmultifilter.xml" />
|
||||
<xi:include href="xml/gtkstringfilter.xml" />
|
||||
<xi:include href="xml/gtkfilefilter.xml" />
|
||||
</section>
|
||||
<xi:include href="xml/gtkflattenlistmodel.xml" />
|
||||
<xi:include href="xml/gtkmaplistmodel.xml" />
|
||||
@@ -285,7 +286,6 @@
|
||||
<xi:include href="xml/gtkfilechoosernative.xml" />
|
||||
<xi:include href="xml/gtkfilechooserdialog.xml" />
|
||||
<xi:include href="xml/gtkfilechooserwidget.xml" />
|
||||
<xi:include href="xml/gtkfilefilter.xml" />
|
||||
<xi:include href="xml/gtkfontchooser.xml" />
|
||||
<xi:include href="xml/gtkfontbutton.xml" />
|
||||
<xi:include href="xml/gtkfontchooserwidget.xml" />
|
||||
|
||||
@@ -348,6 +348,7 @@ GtkBitset
|
||||
gtk_bitset_ref
|
||||
gtk_bitset_unref
|
||||
gtk_bitset_new_empty
|
||||
gtk_bitset_new_range
|
||||
gtk_bitset_copy
|
||||
<SUBSECTION>
|
||||
gtk_bitset_contains
|
||||
@@ -374,7 +375,7 @@ gtk_bitset_subtract
|
||||
gtk_bitset_difference
|
||||
gtk_bitset_shift_left
|
||||
gtk_bitset_shift_right
|
||||
gtk_bitset_slice
|
||||
gtk_bitset_splice
|
||||
<SUBSECTION>
|
||||
GtkBitsetIter
|
||||
gtk_bitset_iter_init_first
|
||||
@@ -422,6 +423,7 @@ gtk_selection_model_get_type
|
||||
GtkNoSelection
|
||||
gtk_no_selection_new
|
||||
gtk_no_selection_get_model
|
||||
gtk_no_selection_set_model
|
||||
<SUBSECTION Private>
|
||||
gtk_no_selection_get_type
|
||||
</SECTION>
|
||||
@@ -433,6 +435,7 @@ GtkSingleSelection
|
||||
GTK_INVALID_LIST_POSITION
|
||||
gtk_single_selection_new
|
||||
gtk_single_selection_get_model
|
||||
gtk_single_selection_set_model
|
||||
gtk_single_selection_get_selected
|
||||
gtk_single_selection_set_selected
|
||||
gtk_single_selection_get_selected_item
|
||||
@@ -450,6 +453,7 @@ gtk_single_selection_get_type
|
||||
GtkMultiSelection
|
||||
gtk_multi_selection_new
|
||||
gtk_multi_selection_get_model
|
||||
gtk_multi_selection_set_model
|
||||
<SUBSECTION Private>
|
||||
gtk_multi_selection_get_type
|
||||
</SECTION>
|
||||
@@ -1306,7 +1310,7 @@ gtk_file_chooser_get_current_folder
|
||||
<SUBSECTION>
|
||||
gtk_file_chooser_add_filter
|
||||
gtk_file_chooser_remove_filter
|
||||
gtk_file_chooser_list_filters
|
||||
gtk_file_chooser_get_filters
|
||||
gtk_file_chooser_set_filter
|
||||
gtk_file_chooser_get_filter
|
||||
<SUBSECTION>
|
||||
@@ -1409,18 +1413,13 @@ GtkFileChooserButtonPrivate
|
||||
<SECTION>
|
||||
<FILE>gtkfilefilter</FILE>
|
||||
GtkFileFilter
|
||||
GtkFileFilterInfo
|
||||
GtkFileFilterFlags
|
||||
GtkFileFilterFunc
|
||||
gtk_file_filter_new
|
||||
gtk_file_filter_set_name
|
||||
gtk_file_filter_get_name
|
||||
gtk_file_filter_add_mime_type
|
||||
gtk_file_filter_add_pattern
|
||||
gtk_file_filter_add_pixbuf_formats
|
||||
gtk_file_filter_add_custom
|
||||
gtk_file_filter_get_needed
|
||||
gtk_file_filter_filter
|
||||
gtk_file_filter_get_attributes
|
||||
|
||||
<SUBSECTION Serialization>
|
||||
gtk_file_filter_new_from_gvariant
|
||||
@@ -1539,11 +1538,13 @@ gtk_custom_filter_get_type
|
||||
<TITLE>GtkFilterListModel</TITLE>
|
||||
GtkFilterListModel
|
||||
gtk_filter_list_model_new
|
||||
gtk_filter_list_model_new_for_type
|
||||
gtk_filter_list_model_set_model
|
||||
gtk_filter_list_model_get_model
|
||||
gtk_filter_list_model_set_filter
|
||||
gtk_filter_list_model_get_filter
|
||||
gtk_filter_list_model_set_incremental
|
||||
gtk_filter_list_model_get_incremental
|
||||
gtk_filter_list_model_get_pending
|
||||
<SUBSECTION Standard>
|
||||
GTK_FILTER_LIST_MODEL
|
||||
GTK_IS_FILTER_LIST_MODEL
|
||||
@@ -2698,7 +2699,6 @@ gtk_size_group_get_type
|
||||
<TITLE>GtkSliceListModel</TITLE>
|
||||
GtkSliceListModel
|
||||
gtk_slice_list_model_new
|
||||
gtk_slice_list_model_new_for_type
|
||||
gtk_slice_list_model_set_model
|
||||
gtk_slice_list_model_get_model
|
||||
gtk_slice_list_model_set_offset
|
||||
@@ -2830,7 +2830,6 @@ gtk_tree_list_row_sorter_get_type
|
||||
<TITLE>GtkSortListModel</TITLE>
|
||||
GtkSortListModel
|
||||
gtk_sort_list_model_new
|
||||
gtk_sort_list_model_new_for_type
|
||||
gtk_sort_list_model_set_sorter
|
||||
gtk_sort_list_model_get_sorter
|
||||
gtk_sort_list_model_set_model
|
||||
@@ -7610,7 +7609,9 @@ gtk_string_list_take
|
||||
gtk_string_list_remove
|
||||
gtk_string_list_splice
|
||||
gtk_string_list_get_string
|
||||
<SUBSECTION>
|
||||
GtkStringObject
|
||||
gtk_string_object_new
|
||||
gtk_string_object_get_string
|
||||
</SECTION>
|
||||
|
||||
|
||||
@@ -295,7 +295,6 @@ gtk_cell_accessible_action_do_action (AtkAction *action,
|
||||
GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
|
||||
GtkCellAccessibleParent *parent;
|
||||
|
||||
cell = GTK_CELL_ACCESSIBLE (action);
|
||||
if (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ static gunichar
|
||||
gtk_password_entry_accessible_get_character_at_offset (AtkText *atk_text,
|
||||
gint offset)
|
||||
{
|
||||
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
|
||||
GtkText *text;
|
||||
char *contents, *index;
|
||||
gunichar result;
|
||||
|
||||
|
||||
@@ -233,6 +233,8 @@
|
||||
#include <gtk/gtkslicelistmodel.h>
|
||||
#include <gtk/gtksnapshot.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
#include <gtk/gtksor2listmodel.h>
|
||||
#include <gtk/gtksor3listmodel.h>
|
||||
#include <gtk/gtksortlistmodel.h>
|
||||
#include <gtk/gtkstacksidebar.h>
|
||||
#include <gtk/gtksizegroup.h>
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
#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
|
||||
+29
-7
@@ -268,7 +268,7 @@ gtk_bitset_get_nth (const GtkBitset *self,
|
||||
*
|
||||
* Creates a new empty bitset.
|
||||
*
|
||||
* Returns: A new empty bitset.
|
||||
* Returns: A new empty bitset
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_new_empty (void)
|
||||
@@ -284,6 +284,28 @@ gtk_bitset_new_empty (void)
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_new_range:
|
||||
* @start: first value to add
|
||||
* @n_items: number of consecutive values to add
|
||||
*
|
||||
* Creates a bitset with the given range set.
|
||||
*
|
||||
* Returns: A new bitset
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_new_range (guint start,
|
||||
guint n_items)
|
||||
{
|
||||
GtkBitset *self;
|
||||
|
||||
self = gtk_bitset_new_empty ();
|
||||
|
||||
gtk_bitset_add_range (self, start, n_items);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_copy:
|
||||
* @self: a #GtkBitset
|
||||
@@ -685,7 +707,7 @@ gtk_bitset_shift_right (GtkBitset *self,
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_slice:
|
||||
* gtk_bitset_splice:
|
||||
* @self: a #GtkBitset
|
||||
* @position: position at which to slice
|
||||
* @removed: number of values to remove
|
||||
@@ -703,10 +725,10 @@ gtk_bitset_shift_right (GtkBitset *self,
|
||||
* up space that can then be filled.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_slice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
gtk_bitset_splice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
/* overflow */
|
||||
@@ -720,7 +742,7 @@ gtk_bitset_slice (GtkBitset *self,
|
||||
GtkBitset *shift = gtk_bitset_copy (self);
|
||||
|
||||
gtk_bitset_remove_range (shift, 0, position);
|
||||
gtk_bitset_remove_range (self, position, G_MAXUINT - position + 1);
|
||||
gtk_bitset_remove_range_closed (self, position, G_MAXUINT);
|
||||
if (added > removed)
|
||||
gtk_bitset_shift_right (shift, added - removed);
|
||||
else
|
||||
|
||||
+4
-1
@@ -65,6 +65,9 @@ GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_new_empty (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_copy (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_new_range (guint start,
|
||||
guint n_items);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_remove_all (GtkBitset *self);
|
||||
@@ -122,7 +125,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_shift_right (GtkBitset *self,
|
||||
guint amount);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_slice (GtkBitset *self,
|
||||
void gtk_bitset_splice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added);
|
||||
|
||||
+13
-15
@@ -391,9 +391,9 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
|
||||
}
|
||||
|
||||
static void
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkArray *tree_rules)
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *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 < tree_rules->len; j++)
|
||||
for (j = 0; j < gtk_css_selector_matches_get_size (tree_rules); j++)
|
||||
{
|
||||
if (ruleset == gtk_array_index (tree_rules, j))
|
||||
if (ruleset == gtk_css_selector_matches_get (tree_rules, j))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -459,22 +459,21 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||
GtkCssRuleset *ruleset;
|
||||
guint j;
|
||||
int i;
|
||||
GtkArray tree_rules_array;
|
||||
GtkCssRuleset *rules_stack[32];
|
||||
GtkCssSelectorMatches tree_rules;
|
||||
|
||||
if (_gtk_css_selector_tree_is_empty (priv->tree))
|
||||
return;
|
||||
|
||||
gtk_array_init (&tree_rules_array, (void**)rules_stack, 32);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules_array);
|
||||
gtk_css_selector_matches_init (&tree_rules);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules);
|
||||
|
||||
if (tree_rules_array.len > 0)
|
||||
if (!gtk_css_selector_matches_is_empty (&tree_rules))
|
||||
{
|
||||
verify_tree_match_results (css_provider, node, &tree_rules_array);
|
||||
verify_tree_match_results (css_provider, node, &tree_rules);
|
||||
|
||||
for (i = tree_rules_array.len - 1; i >= 0; i--)
|
||||
for (i = gtk_css_selector_matches_get_size (&tree_rules) - 1; i >= 0; i--)
|
||||
{
|
||||
ruleset = gtk_array_index (&tree_rules_array, i);
|
||||
ruleset = gtk_css_selector_matches_get (&tree_rules, i);
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
continue;
|
||||
@@ -493,9 +492,8 @@ 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);
|
||||
|
||||
+17
-20
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "gtkcssprovider.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtkarrayimplprivate.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1500
|
||||
@@ -152,14 +151,14 @@ gtk_css_selector_tree_get_matches (const GtkCssSelectorTree *tree)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_insert_sorted (GtkArray *array,
|
||||
gpointer data)
|
||||
gtk_css_selector_matches_insert_sorted (GtkCssSelectorMatches *matches,
|
||||
gpointer data)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < array->len; i++)
|
||||
for (i = 0; i < gtk_css_selector_matches_get_size (matches); i++)
|
||||
{
|
||||
gpointer elem = gtk_array_index (array, i);
|
||||
gpointer elem = gtk_css_selector_matches_get (matches, i);
|
||||
|
||||
if (data == elem)
|
||||
return;
|
||||
@@ -168,7 +167,7 @@ gtk_array_insert_sorted (GtkArray *array,
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_array_insert (array, i, data);
|
||||
gtk_css_selector_matches_splice (matches, i, 0, (gpointer[1]) { data }, 1);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -1877,7 +1876,7 @@ gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
|
||||
|
||||
static void
|
||||
gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
GtkArray *results)
|
||||
GtkCssSelectorMatches *results)
|
||||
{
|
||||
int i;
|
||||
gpointer *matches;
|
||||
@@ -1887,7 +1886,7 @@ gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
return;
|
||||
|
||||
for (i = 0; matches[i] != NULL; i++)
|
||||
gtk_array_insert_sorted (results, matches[i]);
|
||||
gtk_css_selector_matches_insert_sorted (results, matches[i]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1895,7 +1894,7 @@ gtk_css_selector_tree_match (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
gboolean match_filter,
|
||||
GtkCssNode *node,
|
||||
GtkArray *results)
|
||||
GtkCssSelectorMatches *results)
|
||||
{
|
||||
const GtkCssSelectorTree *prev;
|
||||
GtkCssNode *child;
|
||||
@@ -1932,7 +1931,7 @@ void
|
||||
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node,
|
||||
GtkArray *out_tree_rules)
|
||||
GtkCssSelectorMatches *out_tree_rules)
|
||||
{
|
||||
const GtkCssSelectorTree *iter;
|
||||
|
||||
@@ -2117,8 +2116,7 @@ subdivide_infos (GByteArray *array,
|
||||
GHashTableIter iter;
|
||||
guint max_count;
|
||||
gpointer key, value;
|
||||
void *exact_matches_stack[8];
|
||||
GtkArray exact_matches_array;
|
||||
GtkCssSelectorMatches exact_matches;
|
||||
gint32 res;
|
||||
guint i;
|
||||
|
||||
@@ -2160,7 +2158,7 @@ subdivide_infos (GByteArray *array,
|
||||
matched_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
remaining_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
|
||||
gtk_array_init (&exact_matches_array, (void**)exact_matches_stack, 8);
|
||||
gtk_css_selector_matches_init (&exact_matches);
|
||||
for (i = 0; i < n_infos; i++)
|
||||
{
|
||||
GtkCssSelectorRuleSetInfo *info = infos[i];
|
||||
@@ -2171,7 +2169,7 @@ subdivide_infos (GByteArray *array,
|
||||
if (info->current_selector == NULL)
|
||||
{
|
||||
/* Matches current node */
|
||||
gtk_array_add (&exact_matches_array, info->match);
|
||||
gtk_css_selector_matches_append (&exact_matches, info->match);
|
||||
if (info->selector_match != NULL)
|
||||
*info->selector_match = GUINT_TO_POINTER (tree_offset);
|
||||
}
|
||||
@@ -2188,17 +2186,16 @@ subdivide_infos (GByteArray *array,
|
||||
}
|
||||
}
|
||||
|
||||
if (exact_matches_array.len > 0)
|
||||
if (!gtk_css_selector_matches_is_empty (&exact_matches))
|
||||
{
|
||||
gtk_array_add (&exact_matches_array, NULL); /* Null terminate */
|
||||
gtk_css_selector_matches_append (&exact_matches, NULL); /* Null terminate */
|
||||
res = array->len;
|
||||
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);
|
||||
g_byte_array_append (array, (guint8 *) gtk_css_selector_matches_get_data (&exact_matches),
|
||||
gtk_css_selector_matches_get_size (&exact_matches) * sizeof (gpointer));
|
||||
}
|
||||
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,7 +21,12 @@
|
||||
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||
#include "gtk/gtkcsstypesprivate.h"
|
||||
#include "gtk/gtkcssparserprivate.h"
|
||||
#include "gtk/gtkarrayimplprivate.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"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -45,8 +50,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,
|
||||
GtkArray *out_tree_rules);
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *out_tree_rules);
|
||||
GtkCssChange gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node);
|
||||
|
||||
@@ -321,7 +321,7 @@ gtk_custom_paper_unix_dialog_init (GtkCustomPaperUnixDialog *dialog)
|
||||
g_list_store_append (printer_list_list, printer_list);
|
||||
g_object_unref (printer_list);
|
||||
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PRINTER, G_LIST_MODEL (printer_list_list)));
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (printer_list_list)));
|
||||
g_object_unref (printer_list_list);
|
||||
|
||||
filter = gtk_custom_filter_new (match_func, NULL, NULL);
|
||||
|
||||
@@ -224,7 +224,7 @@ gtk_drop_controller_motion_class_init (GtkDropControllerMotionClass *klass)
|
||||
props[PROP_CONTAINS_POINTER] =
|
||||
g_param_spec_boolean ("contains-pointer",
|
||||
P_("Contains Pointer"),
|
||||
P_("Whether the pointer is inthe controllers widget or a descendant"),
|
||||
P_("Whether the pointer is in the controllers widget or a descendant"),
|
||||
FALSE,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
|
||||
+1
-1
@@ -943,7 +943,7 @@ gtk_drop_down_set_from_strings (GtkDropDown *self,
|
||||
|
||||
set_default_factory (self);
|
||||
|
||||
model = G_LIST_MODEL (gtk_string_list_new ((const char **)texts));
|
||||
model = G_LIST_MODEL (gtk_string_list_new (texts));
|
||||
gtk_drop_down_set_model (self, model);
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ gtk_event_controller_motion_class_init (GtkEventControllerMotionClass *klass)
|
||||
props[PROP_CONTAINS_POINTER] =
|
||||
g_param_spec_boolean ("contains-pointer",
|
||||
P_("Contains Pointer"),
|
||||
P_("Whether the pointer is inthe controllers widget or a descendant"),
|
||||
P_("Whether the pointer is in the controllers widget or a descendant"),
|
||||
FALSE,
|
||||
G_PARAM_READABLE);
|
||||
|
||||
|
||||
+50
-15
@@ -168,6 +168,38 @@ gtk_file_chooser_default_init (GtkFileChooserInterface *iface)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:filters:
|
||||
*
|
||||
* A #GListModel containing the filters that have been
|
||||
* added with gtk_file_chooser_add_filter().
|
||||
*
|
||||
* The returned object should not be modified. It may
|
||||
* or may not be updated for later changes.
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_object ("filters",
|
||||
P_("Filters"),
|
||||
P_("List model of filters"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:shortcut-folders:
|
||||
*
|
||||
* A #GListModel containing the shortcut folders that have been
|
||||
* added with gtk_file_chooser_add_shortcut().
|
||||
*
|
||||
* The returned object should not be modified. It may
|
||||
* or may not be updated for later changes.
|
||||
*/
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_object ("shortcut-folders",
|
||||
P_("Shortcut Folders"),
|
||||
P_("List model of shortcut folders"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkFileChooser:create-folders:
|
||||
*
|
||||
@@ -682,23 +714,24 @@ gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_file_chooser_list_filters:
|
||||
* gtk_file_chooser_get_filters:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Lists the current set of user-selectable filters; see
|
||||
* Gets the current set of user-selectable filters, as a list model; see
|
||||
* gtk_file_chooser_add_filter(), gtk_file_chooser_remove_filter().
|
||||
*
|
||||
* Returns: (element-type GtkFileFilter) (transfer container): a
|
||||
* #GSList containing the current set of user selectable filters. The
|
||||
* contents of the list are owned by GTK+, but you must free the list
|
||||
* itself with g_slist_free() when you are done with it.
|
||||
* You should not modify the returned list model. Future changes to
|
||||
* @chooser may or may not affect the returned model.
|
||||
*
|
||||
* Returns: (transfer full): a #GListModel containing the current set
|
||||
* of user-selectable filters.
|
||||
**/
|
||||
GSList *
|
||||
gtk_file_chooser_list_filters (GtkFileChooser *chooser)
|
||||
GListModel *
|
||||
gtk_file_chooser_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_filters (chooser);
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_filters (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -750,21 +783,23 @@ gtk_file_chooser_get_filter (GtkFileChooser *chooser)
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_file_chooser_list_shortcut_folders:
|
||||
* gtk_file_chooser_get_shortcut_folders:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Queries the list of shortcut folders in the file chooser, as set by
|
||||
* gtk_file_chooser_add_shortcut_folder().
|
||||
*
|
||||
* Returns: (nullable) (element-type Gio.File) (transfer full): A list
|
||||
* of folder filenames, or %NULL if there are no shortcut folders.
|
||||
* You should not modify the returned list model. Future changes to
|
||||
* @chooser may or may not affect the returned model.
|
||||
*
|
||||
* Returns: (transfer full): A list model of #GFiles
|
||||
*/
|
||||
GSList *
|
||||
gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
GListModel *
|
||||
gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->list_shortcut_folders (chooser);
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_shortcut_folders (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -145,18 +145,18 @@ GFile * gtk_file_chooser_get_current_folder (GtkFileChooser *chooser);
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GSList *gtk_file_chooser_list_filters (GtkFileChooser *chooser);
|
||||
GListModel *gtk_file_chooser_get_filters (GtkFileChooser *chooser);
|
||||
|
||||
/* Current filter
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_set_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser);
|
||||
|
||||
@@ -164,14 +164,14 @@ GtkFileFilter *gtk_file_chooser_get_filter (GtkFileChooser *chooser);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_chooser_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GFile *folder,
|
||||
GError **error);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GSList *gtk_file_chooser_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
GListModel *gtk_file_chooser_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_chooser_add_choice (GtkFileChooser *chooser,
|
||||
|
||||
@@ -1035,6 +1035,8 @@ gtk_file_chooser_button_get_property (GObject *object,
|
||||
case GTK_FILE_CHOOSER_PROP_FILTER:
|
||||
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
|
||||
case GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS:
|
||||
case GTK_FILE_CHOOSER_PROP_FILTERS:
|
||||
case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS:
|
||||
g_object_get_property (G_OBJECT (button->chooser), pspec->name, value);
|
||||
break;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkfilefilterprivate.h"
|
||||
#include "gtkfilter.h"
|
||||
#include "gtkeventcontrollerfocus.h"
|
||||
|
||||
typedef struct _GtkFileChooserEntryClass GtkFileChooserEntryClass;
|
||||
@@ -194,65 +195,22 @@ match_func (GtkEntryCompletion *compl,
|
||||
* current file filter (e.g. just jpg files) here. */
|
||||
if (chooser_entry->current_filter != NULL)
|
||||
{
|
||||
char *mime_type = NULL;
|
||||
gboolean matches;
|
||||
GFile *file;
|
||||
GFileInfo *file_info;
|
||||
GtkFileFilterInfo filter_info;
|
||||
GtkFileFilterFlags needed_flags;
|
||||
GFileInfo *info;
|
||||
|
||||
file = _gtk_file_system_model_get_file (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
file_info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
info = _gtk_file_system_model_get_info (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
iter);
|
||||
|
||||
/* We always allow navigating into subfolders, so don't ever filter directories */
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR)
|
||||
if (g_file_info_get_file_type (info) != G_FILE_TYPE_REGULAR)
|
||||
return TRUE;
|
||||
|
||||
needed_flags = gtk_file_filter_get_needed (chooser_entry->current_filter);
|
||||
if (!g_file_info_has_attribute (info, "standard::file"))
|
||||
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
|
||||
|
||||
filter_info.display_name = g_file_info_get_display_name (file_info);
|
||||
filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_MIME_TYPE)
|
||||
{
|
||||
const char *s = g_file_info_get_content_type (file_info);
|
||||
if (s != NULL)
|
||||
{
|
||||
mime_type = g_content_type_get_mime_type (s);
|
||||
if (mime_type != NULL)
|
||||
{
|
||||
filter_info.mime_type = mime_type;
|
||||
filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_FILENAME)
|
||||
{
|
||||
const char *path = g_file_get_path (file);
|
||||
if (path != NULL)
|
||||
{
|
||||
filter_info.filename = path;
|
||||
filter_info.contains |= GTK_FILE_FILTER_FILENAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (needed_flags & GTK_FILE_FILTER_URI)
|
||||
{
|
||||
const char *uri = g_file_get_uri (file);
|
||||
if (uri)
|
||||
{
|
||||
filter_info.uri = uri;
|
||||
filter_info.contains |= GTK_FILE_FILTER_URI;
|
||||
}
|
||||
}
|
||||
|
||||
matches = gtk_file_filter_filter (chooser_entry->current_filter, &filter_info);
|
||||
|
||||
g_free (mime_type);
|
||||
return matches;
|
||||
return gtk_filter_match (GTK_FILTER (chooser_entry->current_filter), info);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -126,7 +126,7 @@ response_cb (GDBusConnection *connection,
|
||||
if (current_filter)
|
||||
{
|
||||
GtkFileFilter *filter = gtk_file_filter_new_from_gvariant (current_filter);
|
||||
const gchar *current_filter_name = gtk_file_filter_get_name (filter);
|
||||
const char *current_filter_name = gtk_file_filter_get_name (filter);
|
||||
|
||||
/* Try to find the given filter in the list of filters.
|
||||
* Since filters are compared by pointer value, using the passed
|
||||
@@ -137,18 +137,24 @@ response_cb (GDBusConnection *connection,
|
||||
* If there is no match, just set the filter as it was retrieved.
|
||||
*/
|
||||
GtkFileFilter *filter_to_select = filter;
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
for (GSList *l = filters; l; l = l->next)
|
||||
GListModel *filters;
|
||||
guint j, n;
|
||||
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (j = 0; j < n; j++)
|
||||
{
|
||||
GtkFileFilter *f = l->data;
|
||||
GtkFileFilter *f = g_list_model_get_item (filters, j);
|
||||
if (g_strcmp0 (gtk_file_filter_get_name (f), current_filter_name) == 0)
|
||||
{
|
||||
filter_to_select = f;
|
||||
break;
|
||||
}
|
||||
g_object_unref (f);
|
||||
}
|
||||
g_slist_free (filters);
|
||||
g_object_unref (filters);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (self), filter_to_select);
|
||||
g_object_unref (filter_to_select);
|
||||
}
|
||||
|
||||
g_slist_free_full (self->custom_files, g_object_unref);
|
||||
@@ -264,17 +270,20 @@ open_file_msg_cb (GObject *source_object,
|
||||
static GVariant *
|
||||
get_filters (GtkFileChooser *self)
|
||||
{
|
||||
GSList *list, *l;
|
||||
GListModel *filters;
|
||||
guint n, i;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa(us))"));
|
||||
list = gtk_file_chooser_list_filters (self);
|
||||
for (l = list; l; l = l->next)
|
||||
filters = gtk_file_chooser_get_filters (self);
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkFileFilter *filter = l->data;
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
g_variant_builder_add (&builder, "@(sa(us))", gtk_file_filter_to_gvariant (filter));
|
||||
g_object_unref (filter);
|
||||
}
|
||||
g_slist_free (list);
|
||||
g_object_unref (filters);
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
@@ -99,9 +99,10 @@ typedef struct {
|
||||
else
|
||||
[data->panel setAllowedFileTypes:filter];
|
||||
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
data->self->current_filter = g_slist_nth_data (filters, selected_index);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
data->self->current_filter = g_list_model_get_item (filters, selected_index);
|
||||
g_object_unref (data->self->current_filter);
|
||||
g_object_unref (filters);
|
||||
g_object_notify (G_OBJECT (data->self), "filter");
|
||||
}
|
||||
@end
|
||||
@@ -307,13 +308,28 @@ filechooser_quartz_launch (FileChooserQuartzData *data)
|
||||
|
||||
if (data->self->current_filter)
|
||||
{
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
gint current_filter_index = g_slist_index (filters, data->self->current_filter);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters;
|
||||
guint i, n;
|
||||
guint current_filter_index = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
if (current_filter_index >= 0)
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
n = g_list_model_get_n_items (filters);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (filters, i);
|
||||
if (item == data->self->current_filter)
|
||||
{
|
||||
g_object_unref (item);
|
||||
current_filter_index = i;
|
||||
break;
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
if (current_filter_index != GTK_INVALID_LIST_POSITION)
|
||||
[data->filter_combo_box selectItemAtIndex:current_filter_index];
|
||||
else
|
||||
else
|
||||
[data->filter_combo_box selectItemAtIndex:0];
|
||||
}
|
||||
else
|
||||
@@ -437,15 +453,15 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
GtkWindow *transient_for;
|
||||
GtkFileChooserAction action;
|
||||
|
||||
GSList *filters, *l;
|
||||
int n_filters, i;
|
||||
GListModel *filters;
|
||||
guint n_filters, i;
|
||||
char *message = NULL;
|
||||
|
||||
data = g_new0 (FileChooserQuartzData, 1);
|
||||
|
||||
// examine filters!
|
||||
filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_slist_length (filters);
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_list_model_get_n_items (filters);
|
||||
if (n_filters > 0)
|
||||
{
|
||||
data->filters = [NSMutableArray arrayWithCapacity:n_filters];
|
||||
@@ -453,13 +469,17 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
data->filter_names = [NSMutableArray arrayWithCapacity:n_filters];
|
||||
[data->filter_names retain];
|
||||
|
||||
for (l = filters, i = 0; l != NULL; l = l->next, i++)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (!file_filter_to_quartz (l->data, data->filters, data->filter_names))
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
if (!file_filter_to_quartz (filter, data->filters, data->filter_names))
|
||||
{
|
||||
filechooser_quartz_data_free (data);
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
return FALSE;
|
||||
}
|
||||
g_object_unref (filter);
|
||||
}
|
||||
self->current_filter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (self));
|
||||
}
|
||||
@@ -467,6 +487,8 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
|
||||
{
|
||||
self->current_filter = NULL;
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
self->mode_data = data;
|
||||
data->self = g_object_ref (self);
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ typedef struct {
|
||||
char *cancel_label;
|
||||
char *title;
|
||||
|
||||
GSList *shortcut_files;
|
||||
GListModel *shortcut_files;
|
||||
GArray *choices_selections;
|
||||
|
||||
GFile *current_folder;
|
||||
@@ -244,9 +244,11 @@ ifiledialogevents_OnTypeChange (IFileDialogEvents * self,
|
||||
return S_OK;
|
||||
}
|
||||
fileType--; // fileTypeIndex starts at 1
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (events->data->self));
|
||||
events->data->self->current_filter = g_slist_nth_data (filters, fileType);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (events->data->self));
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, fileType);
|
||||
events->data->self->current_filter = filter;
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
g_object_notify (G_OBJECT (events->data->self), "filter");
|
||||
return S_OK;
|
||||
}
|
||||
@@ -328,7 +330,7 @@ filechooser_win32_thread_data_free (FilechooserWin32ThreadData *data)
|
||||
g_array_free (data->choices_selections, TRUE);
|
||||
data->choices_selections = NULL;
|
||||
}
|
||||
g_slist_free_full (data->shortcut_files, g_object_unref);
|
||||
g_object_unref (data->shortcut_files);
|
||||
g_slist_free_full (data->files, g_object_unref);
|
||||
if (data->self)
|
||||
g_object_unref (data->self);
|
||||
@@ -463,7 +465,7 @@ filechooser_win32_thread (gpointer _data)
|
||||
IFileDialog2 *pfd2 = NULL;
|
||||
DWORD flags;
|
||||
DWORD cookie;
|
||||
GSList *l;
|
||||
guint j, n_items;
|
||||
|
||||
CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
@@ -529,9 +531,11 @@ filechooser_win32_thread (gpointer _data)
|
||||
g_free (label);
|
||||
}
|
||||
|
||||
for (l = data->shortcut_files; l != NULL; l = l->next)
|
||||
n_items = g_list_model_get_n_items (data->shortcut_files);
|
||||
for (j = 0; j < n_items; j++)
|
||||
{
|
||||
IShellItem *item = get_shell_item_for_file (l->data);
|
||||
GFile *file = g_list_model_get_item (data->shortcut_files, j);
|
||||
IShellItem *item = get_shell_item_for_file (file);
|
||||
if (item)
|
||||
{
|
||||
hr = IFileDialog_AddPlace (pfd, item, FDAP_BOTTOM);
|
||||
@@ -539,6 +543,7 @@ filechooser_win32_thread (gpointer _data)
|
||||
g_warning_hr ("Can't add dialog shortcut", hr);
|
||||
IShellItem_Release (item);
|
||||
}
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
if (data->current_file)
|
||||
@@ -591,9 +596,23 @@ filechooser_win32_thread (gpointer _data)
|
||||
|
||||
if (data->self->current_filter)
|
||||
{
|
||||
GSList *filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (data->self));
|
||||
gint current_filter_index = g_slist_index (filters, data->self->current_filter);
|
||||
g_slist_free (filters);
|
||||
GListModel *filters;
|
||||
guint current_filter_index = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (data->self));
|
||||
n_items = g_list_model_get_n_items (filters);
|
||||
for (j = 0; j < n_items; j++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (filters, j);
|
||||
if (item == data->self->current_filter)
|
||||
{
|
||||
current_filter_index = j;
|
||||
g_object_unref (item);
|
||||
break;
|
||||
}
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
if (current_filter_index >= 0)
|
||||
hr = IFileDialog_SetFileTypeIndex (pfd, current_filter_index + 1);
|
||||
@@ -617,6 +636,8 @@ filechooser_win32_thread (gpointer _data)
|
||||
hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = data->self->choices; l; l = l->next, dialog_control_id++)
|
||||
{
|
||||
GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data;
|
||||
@@ -742,6 +763,8 @@ filechooser_win32_thread (gpointer _data)
|
||||
hr = IFileDialog_QueryInterface (pfd, &IID_IFileDialogCustomize, (LPVOID *) &pfdc);
|
||||
if (SUCCEEDED (hr))
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = data->self->choices; l; l = l->next)
|
||||
{
|
||||
GtkFileChooserNativeChoice *choice = (GtkFileChooserNativeChoice*) l->data;
|
||||
@@ -864,21 +887,24 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
|
||||
FilechooserWin32ThreadData *data;
|
||||
GtkWindow *transient_for;
|
||||
GtkFileChooserAction action;
|
||||
GSList *filters, *l;
|
||||
int n_filters, i;
|
||||
GListModel *filters;
|
||||
guint n_filters, i;
|
||||
|
||||
data = g_new0 (FilechooserWin32ThreadData, 1);
|
||||
|
||||
filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_slist_length (filters);
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (self));
|
||||
n_filters = g_list_model_get_n_items (filters);
|
||||
if (n_filters > 0)
|
||||
{
|
||||
data->filters = g_new0 (COMDLG_FILTERSPEC, n_filters + 1);
|
||||
|
||||
for (l = filters, i = 0; l != NULL; l = l->next, i++)
|
||||
for (i = 0; i < n_filters; i++)
|
||||
{
|
||||
if (!file_filter_to_win32 (l->data, &data->filters[i]))
|
||||
GtkFileFilter *filter = g_list_model_get_item (filters, i);
|
||||
if (!file_filter_to_win32 (filter, &data->filters[i]))
|
||||
{
|
||||
g_object_unref (filter);
|
||||
g_object_unref (filters);
|
||||
filechooser_win32_thread_data_free (data);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -889,12 +915,13 @@ gtk_file_chooser_native_win32_show (GtkFileChooserNative *self)
|
||||
{
|
||||
self->current_filter = NULL;
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
self->mode_data = data;
|
||||
data->self = g_object_ref (self);
|
||||
|
||||
data->shortcut_files =
|
||||
gtk_file_chooser_list_shortcut_folders (GTK_FILE_CHOOSER (self->dialog));
|
||||
gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (self->dialog));
|
||||
|
||||
data->accept_label = translate_mnemonics (self->accept_label);
|
||||
data->cancel_label = translate_mnemonics (self->cancel_label);
|
||||
|
||||
+25
-25
@@ -58,34 +58,34 @@ struct _GtkFileChooserIface
|
||||
|
||||
/* Methods
|
||||
*/
|
||||
gboolean (*set_current_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile * (*get_current_folder) (GtkFileChooser *chooser);
|
||||
void (*set_current_name) (GtkFileChooser *chooser,
|
||||
const gchar *name);
|
||||
gboolean (*set_current_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile * (*get_current_folder) (GtkFileChooser *chooser);
|
||||
void (*set_current_name) (GtkFileChooser *chooser,
|
||||
const gchar *name);
|
||||
gchar * (*get_current_name) (GtkFileChooser *chooser);
|
||||
gboolean (*select_file) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
void (*unselect_file) (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
void (*select_all) (GtkFileChooser *chooser);
|
||||
void (*unselect_all) (GtkFileChooser *chooser);
|
||||
GSList * (*get_files) (GtkFileChooser *chooser);
|
||||
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
|
||||
void (*add_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
void (*remove_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GSList * (*list_filters) (GtkFileChooser *chooser);
|
||||
gboolean (*select_file) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
void (*unselect_file) (GtkFileChooser *chooser,
|
||||
GFile *file);
|
||||
void (*select_all) (GtkFileChooser *chooser);
|
||||
void (*unselect_all) (GtkFileChooser *chooser);
|
||||
GSList * (*get_files) (GtkFileChooser *chooser);
|
||||
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
|
||||
void (*add_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
void (*remove_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
GListModel * (*get_filters) (GtkFileChooser *chooser);
|
||||
gboolean (*add_shortcut_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GFile *file,
|
||||
GError **error);
|
||||
gboolean (*remove_shortcut_folder) (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GSList * (*list_shortcut_folders) (GtkFileChooser *chooser);
|
||||
GFile *file,
|
||||
GError **error);
|
||||
GListModel * (*get_shortcut_folders) (GtkFileChooser *chooser);
|
||||
|
||||
/* Signals
|
||||
*/
|
||||
|
||||
+24
-18
@@ -45,14 +45,14 @@ static void delegate_add_filter (GtkFileChooser *choose
|
||||
GtkFileFilter *filter);
|
||||
static void delegate_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static GSList * delegate_list_filters (GtkFileChooser *chooser);
|
||||
static GListModel * delegate_get_filters (GtkFileChooser *chooser);
|
||||
static gboolean delegate_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static gboolean delegate_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static GSList * delegate_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
static GListModel * delegate_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
static void delegate_notify (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer data);
|
||||
@@ -92,17 +92,23 @@ void
|
||||
_gtk_file_chooser_install_properties (GObjectClass *klass)
|
||||
{
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_ACTION,
|
||||
"action");
|
||||
GTK_FILE_CHOOSER_PROP_ACTION,
|
||||
"action");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
"filter");
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
"filter");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
"select-multiple");
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
"select-multiple");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
"create-folders");
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
"create-folders");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_FILTERS,
|
||||
"filters");
|
||||
g_object_class_override_property (klass,
|
||||
GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS,
|
||||
"shortcut-folders");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,10 +137,10 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
|
||||
iface->get_file_system = delegate_get_file_system;
|
||||
iface->add_filter = delegate_add_filter;
|
||||
iface->remove_filter = delegate_remove_filter;
|
||||
iface->list_filters = delegate_list_filters;
|
||||
iface->get_filters = delegate_get_filters;
|
||||
iface->add_shortcut_folder = delegate_add_shortcut_folder;
|
||||
iface->remove_shortcut_folder = delegate_remove_shortcut_folder;
|
||||
iface->list_shortcut_folders = delegate_list_shortcut_folders;
|
||||
iface->get_shortcut_folders = delegate_get_shortcut_folders;
|
||||
iface->add_choice = delegate_add_choice;
|
||||
iface->remove_choice = delegate_remove_choice;
|
||||
iface->set_choice = delegate_set_choice;
|
||||
@@ -241,10 +247,10 @@ delegate_remove_filter (GtkFileChooser *chooser,
|
||||
gtk_file_chooser_remove_filter (get_delegate (chooser), filter);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
delegate_list_filters (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
delegate_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
return gtk_file_chooser_list_filters (get_delegate (chooser));
|
||||
return gtk_file_chooser_get_filters (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -263,10 +269,10 @@ delegate_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
return gtk_file_chooser_remove_shortcut_folder (get_delegate (chooser), file, error);
|
||||
}
|
||||
|
||||
static GSList *
|
||||
delegate_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
delegate_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
return gtk_file_chooser_list_shortcut_folders (get_delegate (chooser));
|
||||
return gtk_file_chooser_get_shortcut_folders (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -32,7 +32,9 @@ typedef enum {
|
||||
GTK_FILE_CHOOSER_PROP_FILTER,
|
||||
GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE,
|
||||
GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS,
|
||||
GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_CREATE_FOLDERS
|
||||
GTK_FILE_CHOOSER_PROP_FILTERS,
|
||||
GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS,
|
||||
GTK_FILE_CHOOSER_PROP_LAST = GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS
|
||||
} GtkFileChooserProp;
|
||||
|
||||
void _gtk_file_chooser_install_properties (GObjectClass *klass);
|
||||
|
||||
+39
-28
@@ -485,14 +485,14 @@ static void gtk_file_chooser_widget_add_filter (GtkF
|
||||
GtkFileFilter *filter);
|
||||
static void gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
static GSList * gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser);
|
||||
static GListModel * gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser);
|
||||
static gboolean gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static gboolean gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GFile *file,
|
||||
GError **error);
|
||||
static GSList * gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser);
|
||||
static GListModel * gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser);
|
||||
|
||||
static gboolean gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed);
|
||||
static void gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed);
|
||||
@@ -619,10 +619,10 @@ gtk_file_chooser_widget_iface_init (GtkFileChooserIface *iface)
|
||||
iface->get_current_name = gtk_file_chooser_widget_get_current_name;
|
||||
iface->add_filter = gtk_file_chooser_widget_add_filter;
|
||||
iface->remove_filter = gtk_file_chooser_widget_remove_filter;
|
||||
iface->list_filters = gtk_file_chooser_widget_list_filters;
|
||||
iface->get_filters = gtk_file_chooser_widget_get_filters;
|
||||
iface->add_shortcut_folder = gtk_file_chooser_widget_add_shortcut_folder;
|
||||
iface->remove_shortcut_folder = gtk_file_chooser_widget_remove_shortcut_folder;
|
||||
iface->list_shortcut_folders = gtk_file_chooser_widget_list_shortcut_folders;
|
||||
iface->get_shortcut_folders = gtk_file_chooser_widget_get_shortcut_folders;
|
||||
iface->add_choice = gtk_file_chooser_widget_add_choice;
|
||||
iface->remove_choice = gtk_file_chooser_widget_remove_choice;
|
||||
iface->set_choice = gtk_file_chooser_widget_set_choice;
|
||||
@@ -3072,6 +3072,14 @@ gtk_file_chooser_widget_get_property (GObject *object,
|
||||
g_value_set_boolean (value, impl->create_folders);
|
||||
break;
|
||||
|
||||
case GTK_FILE_CHOOSER_PROP_FILTERS:
|
||||
g_value_set_object (value, impl->filters);
|
||||
break;
|
||||
|
||||
case GTK_FILE_CHOOSER_PROP_SHORTCUT_FOLDERS:
|
||||
g_value_take_object (value, gtk_file_chooser_get_shortcut_folders (GTK_FILE_CHOOSER (impl)));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -3429,25 +3437,27 @@ set_startup_mode (GtkFileChooserWidget *impl)
|
||||
static gboolean
|
||||
shortcut_exists (GtkFileChooserWidget *impl, GFile *needle)
|
||||
{
|
||||
GSList *haystack;
|
||||
GSList *l;
|
||||
GListModel *haystack;
|
||||
guint n, i;
|
||||
gboolean exists;
|
||||
|
||||
exists = FALSE;
|
||||
|
||||
haystack = gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
for (l = haystack; l; l = l->next)
|
||||
haystack = gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
n = g_list_model_get_n_items (haystack);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GFile *hay;
|
||||
GFile *hay = g_list_model_get_item (haystack, i);
|
||||
|
||||
hay = G_FILE (l->data);
|
||||
if (g_file_equal (hay, needle))
|
||||
{
|
||||
g_object_unref (hay);
|
||||
exists = TRUE;
|
||||
break;
|
||||
}
|
||||
g_object_unref (hay);
|
||||
}
|
||||
g_slist_free_full (haystack, g_object_unref);
|
||||
g_object_unref (haystack);
|
||||
|
||||
return exists;
|
||||
}
|
||||
@@ -5564,6 +5574,8 @@ gtk_file_chooser_widget_add_filter (GtkFileChooser *chooser,
|
||||
set_current_filter (impl, filter);
|
||||
|
||||
show_filters (impl, TRUE);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "filters");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -5597,25 +5609,16 @@ gtk_file_chooser_widget_remove_filter (GtkFileChooser *chooser,
|
||||
|
||||
if (!impl->filters)
|
||||
show_filters (impl, FALSE);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "filters");
|
||||
}
|
||||
|
||||
static GSList *
|
||||
gtk_file_chooser_widget_list_filters (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
gtk_file_chooser_widget_get_filters (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
GSList *filters;
|
||||
guint i;
|
||||
|
||||
filters = NULL;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (impl->filters)); i++)
|
||||
{
|
||||
GtkFileFilter *filter = g_list_model_get_item (G_LIST_MODEL (impl->filters), i);
|
||||
filters = g_slist_append (filters, filter);
|
||||
g_object_unref (filter);
|
||||
}
|
||||
|
||||
return filters;
|
||||
return G_LIST_MODEL (g_object_ref (impl->filters));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -5626,6 +5629,9 @@ gtk_file_chooser_widget_add_shortcut_folder (GtkFileChooser *chooser,
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
gtk_places_sidebar_add_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "shortcut-folders");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -5637,15 +5643,18 @@ gtk_file_chooser_widget_remove_shortcut_folder (GtkFileChooser *chooser,
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
gtk_places_sidebar_remove_shortcut (GTK_PLACES_SIDEBAR (impl->places_sidebar), file);
|
||||
|
||||
g_object_notify (G_OBJECT (chooser), "shortcut-folders");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
gtk_file_chooser_widget_list_shortcut_folders (GtkFileChooser *chooser)
|
||||
static GListModel *
|
||||
gtk_file_chooser_widget_get_shortcut_folders (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
|
||||
|
||||
return gtk_places_sidebar_list_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
return gtk_places_sidebar_get_shortcuts (GTK_PLACES_SIDEBAR (impl->places_sidebar));
|
||||
}
|
||||
|
||||
struct switch_folder_closure {
|
||||
@@ -6933,6 +6942,8 @@ filter_combo_changed (GtkDropDown *dropdown,
|
||||
|
||||
new_filter = gtk_drop_down_get_selected_item (dropdown);
|
||||
|
||||
set_current_filter (impl, new_filter);
|
||||
|
||||
if (impl->location_entry != NULL)
|
||||
_gtk_file_chooser_entry_set_file_filter (GTK_FILE_CHOOSER_ENTRY (impl->location_entry),
|
||||
new_filter);
|
||||
|
||||
+336
-373
File diff suppressed because it is too large
Load Diff
+13
-78
@@ -33,99 +33,34 @@ G_BEGIN_DECLS
|
||||
#define GTK_IS_FILE_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FILTER))
|
||||
|
||||
typedef struct _GtkFileFilter GtkFileFilter;
|
||||
typedef struct _GtkFileFilterInfo GtkFileFilterInfo;
|
||||
|
||||
/**
|
||||
* GtkFileFilterFlags:
|
||||
* @GTK_FILE_FILTER_FILENAME: the filename of the file being tested
|
||||
* @GTK_FILE_FILTER_URI: the URI for the file being tested
|
||||
* @GTK_FILE_FILTER_DISPLAY_NAME: the string that will be used to
|
||||
* display the file in the file chooser
|
||||
* @GTK_FILE_FILTER_MIME_TYPE: the mime type of the file
|
||||
*
|
||||
* These flags indicate what parts of a #GtkFileFilterInfo struct
|
||||
* are filled or need to be filled.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_FILE_FILTER_FILENAME = 1 << 0,
|
||||
GTK_FILE_FILTER_URI = 1 << 1,
|
||||
GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
|
||||
GTK_FILE_FILTER_MIME_TYPE = 1 << 3
|
||||
} GtkFileFilterFlags;
|
||||
|
||||
/**
|
||||
* GtkFileFilterFunc:
|
||||
* @filter_info: a #GtkFileFilterInfo that is filled according
|
||||
* to the @needed flags passed to gtk_file_filter_add_custom()
|
||||
* @data: (closure): user data passed to gtk_file_filter_add_custom()
|
||||
*
|
||||
* The type of function that is used with custom filters, see
|
||||
* gtk_file_filter_add_custom().
|
||||
*
|
||||
* Returns: %TRUE if the file should be displayed
|
||||
*/
|
||||
typedef gboolean (*GtkFileFilterFunc) (const GtkFileFilterInfo *filter_info,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* GtkFileFilterInfo:
|
||||
* @contains: Flags indicating which of the following fields need
|
||||
* are filled
|
||||
* @filename: the filename of the file being tested
|
||||
* @uri: the URI for the file being tested
|
||||
* @display_name: the string that will be used to display the file
|
||||
* in the file chooser
|
||||
* @mime_type: the mime type of the file
|
||||
*
|
||||
* A #GtkFileFilterInfo is used to pass information about the
|
||||
* tested file to gtk_file_filter_filter().
|
||||
*/
|
||||
struct _GtkFileFilterInfo
|
||||
{
|
||||
GtkFileFilterFlags contains;
|
||||
|
||||
const gchar *filename;
|
||||
const gchar *uri;
|
||||
const gchar *display_name;
|
||||
const gchar *mime_type;
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_file_filter_get_type (void) G_GNUC_CONST;
|
||||
GType gtk_file_filter_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter * gtk_file_filter_new (void);
|
||||
GtkFileFilter * gtk_file_filter_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_set_name (GtkFileFilter *filter,
|
||||
const gchar *name);
|
||||
void gtk_file_filter_set_name (GtkFileFilter *filter,
|
||||
const char *name);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const gchar * gtk_file_filter_get_name (GtkFileFilter *filter);
|
||||
const char * gtk_file_filter_get_name (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_mime_type (GtkFileFilter *filter,
|
||||
const gchar *mime_type);
|
||||
void gtk_file_filter_add_mime_type (GtkFileFilter *filter,
|
||||
const char *mime_type);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_pattern (GtkFileFilter *filter,
|
||||
const gchar *pattern);
|
||||
void gtk_file_filter_add_pattern (GtkFileFilter *filter,
|
||||
const char *pattern);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_file_filter_add_custom (GtkFileFilter *filter,
|
||||
GtkFileFilterFlags needed,
|
||||
GtkFileFilterFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void gtk_file_filter_add_pixbuf_formats (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilterFlags gtk_file_filter_get_needed (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_file_filter_filter (GtkFileFilter *filter,
|
||||
const GtkFileFilterInfo *filter_info);
|
||||
const char ** gtk_file_filter_get_attributes (GtkFileFilter *filter);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GVariant *gtk_file_filter_to_gvariant (GtkFileFilter *filter);
|
||||
GVariant * gtk_file_filter_to_gvariant (GtkFileFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFileFilter *gtk_file_filter_new_from_gvariant (GVariant *variant);
|
||||
GtkFileFilter * gtk_file_filter_new_from_gvariant (GVariant *variant);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "gtktreedatalist.h"
|
||||
#include "gtktreednd.h"
|
||||
#include "gtktreemodel.h"
|
||||
#include "gtkfilter.h"
|
||||
|
||||
/*** Structure: how GtkFileSystemModel works
|
||||
*
|
||||
@@ -375,12 +376,6 @@ static gboolean
|
||||
node_should_be_filtered_out (GtkFileSystemModel *model, guint id)
|
||||
{
|
||||
FileModelNode *node = get_node (model, id);
|
||||
GtkFileFilterInfo filter_info = { 0, };
|
||||
GtkFileFilterFlags required;
|
||||
gboolean result;
|
||||
char *mime_type = NULL;
|
||||
char *filename = NULL;
|
||||
char *uri = NULL;
|
||||
|
||||
if (node->info == NULL)
|
||||
return TRUE;
|
||||
@@ -388,57 +383,10 @@ node_should_be_filtered_out (GtkFileSystemModel *model, guint id)
|
||||
if (model->filter == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* fill info */
|
||||
required = gtk_file_filter_get_needed (model->filter);
|
||||
if (!g_file_info_has_attribute (node->info, "standard::file"))
|
||||
g_file_info_set_attribute_object (node->info, "standard::file", G_OBJECT (node->file));
|
||||
|
||||
filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
|
||||
filter_info.display_name = g_file_info_get_display_name (node->info);
|
||||
|
||||
if (required & GTK_FILE_FILTER_MIME_TYPE)
|
||||
{
|
||||
const char *s = g_file_info_get_content_type (node->info);
|
||||
|
||||
if (!s)
|
||||
s = g_file_info_get_attribute_string (node->info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
|
||||
|
||||
if (s)
|
||||
{
|
||||
mime_type = g_content_type_get_mime_type (s);
|
||||
if (mime_type)
|
||||
{
|
||||
filter_info.mime_type = mime_type;
|
||||
filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (required & GTK_FILE_FILTER_FILENAME)
|
||||
{
|
||||
filename = g_file_get_path (node->file);
|
||||
if (filename)
|
||||
{
|
||||
filter_info.filename = filename;
|
||||
filter_info.contains |= GTK_FILE_FILTER_FILENAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (required & GTK_FILE_FILTER_URI)
|
||||
{
|
||||
uri = g_file_get_uri (node->file);
|
||||
if (uri)
|
||||
{
|
||||
filter_info.uri = uri;
|
||||
filter_info.contains |= GTK_FILE_FILTER_URI;
|
||||
}
|
||||
}
|
||||
|
||||
result = !gtk_file_filter_filter (model->filter, &filter_info);
|
||||
|
||||
g_free (mime_type);
|
||||
g_free (filename);
|
||||
g_free (uri);
|
||||
|
||||
return result;
|
||||
return !gtk_filter_match (GTK_FILTER (model->filter), node->info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
||||
+329
-392
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "gtkfilterlistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
@@ -35,40 +35,33 @@
|
||||
* listmodel.
|
||||
* It hides some elements from the other model according to
|
||||
* criteria given by a #GtkFilter.
|
||||
*
|
||||
* The model can be set up to do incremental searching, so that
|
||||
* filtering long lists doesn't block the UI. See
|
||||
* gtk_filter_list_model_set_incremental() for details.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_FILTER,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_INCREMENTAL,
|
||||
PROP_MODEL,
|
||||
PROP_PENDING,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
typedef struct _FilterNode FilterNode;
|
||||
typedef struct _FilterAugment FilterAugment;
|
||||
|
||||
struct _FilterNode
|
||||
{
|
||||
guint visible : 1;
|
||||
};
|
||||
|
||||
struct _FilterAugment
|
||||
{
|
||||
guint n_items;
|
||||
guint n_visible;
|
||||
};
|
||||
|
||||
struct _GtkFilterListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkFilter *filter;
|
||||
GtkFilterMatch strictness;
|
||||
gboolean incremental;
|
||||
|
||||
GtkRbTree *items; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||
GtkBitset *matches; /* NULL if strictness != GTK_FILTER_MATCH_SOME */
|
||||
GtkBitset *pending; /* not yet filtered items or NULL if all filtered */
|
||||
guint pending_cb; /* idle callback handle */
|
||||
};
|
||||
|
||||
struct _GtkFilterListModelClass
|
||||
@@ -78,133 +71,16 @@ struct _GtkFilterListModelClass
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_augment (GtkRbTree *filter,
|
||||
gpointer _aug,
|
||||
gpointer _node,
|
||||
gpointer left,
|
||||
gpointer right)
|
||||
{
|
||||
FilterNode *node = _node;
|
||||
FilterAugment *aug = _aug;
|
||||
|
||||
aug->n_items = 1;
|
||||
aug->n_visible = node->visible ? 1 : 0;
|
||||
|
||||
if (left)
|
||||
{
|
||||
FilterAugment *left_aug = gtk_rb_tree_get_augment (filter, left);
|
||||
aug->n_items += left_aug->n_items;
|
||||
aug->n_visible += left_aug->n_visible;
|
||||
}
|
||||
if (right)
|
||||
{
|
||||
FilterAugment *right_aug = gtk_rb_tree_get_augment (filter, right);
|
||||
aug->n_items += right_aug->n_items;
|
||||
aug->n_visible += right_aug->n_visible;
|
||||
}
|
||||
}
|
||||
|
||||
static FilterNode *
|
||||
gtk_filter_list_model_get_nth_filtered (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *out_unfiltered)
|
||||
{
|
||||
FilterNode *node, *tmp;
|
||||
guint unfiltered;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
unfiltered = 0;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_visible)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_visible;
|
||||
unfiltered += aug->n_items;
|
||||
}
|
||||
|
||||
if (node->visible)
|
||||
{
|
||||
if (position == 0)
|
||||
break;
|
||||
position--;
|
||||
}
|
||||
|
||||
unfiltered++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (out_unfiltered)
|
||||
*out_unfiltered = unfiltered;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static FilterNode *
|
||||
gtk_filter_list_model_get_nth (GtkRbTree *tree,
|
||||
guint position,
|
||||
guint *out_filtered)
|
||||
{
|
||||
FilterNode *node, *tmp;
|
||||
guint filtered;
|
||||
|
||||
node = gtk_rb_tree_get_root (tree);
|
||||
filtered = 0;
|
||||
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
FilterAugment *aug = gtk_rb_tree_get_augment (tree, tmp);
|
||||
if (position < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
position -= aug->n_items;
|
||||
filtered += aug->n_visible;
|
||||
}
|
||||
|
||||
if (position == 0)
|
||||
break;
|
||||
|
||||
position--;
|
||||
if (node->visible)
|
||||
filtered++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
if (out_filtered)
|
||||
*out_filtered = filtered;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_filter_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkFilterListModel *self = GTK_FILTER_LIST_MODEL (list);
|
||||
FilterAugment *aug;
|
||||
FilterNode *node;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
@@ -215,18 +91,12 @@ gtk_filter_list_model_get_n_items (GListModel *list)
|
||||
return g_list_model_get_n_items (self->model);
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
break;
|
||||
return gtk_bitset_get_size (self->matches);
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = gtk_rb_tree_get_root (self->items);
|
||||
if (node == NULL)
|
||||
return 0;
|
||||
|
||||
aug = gtk_rb_tree_get_augment (self->items, node);
|
||||
return aug->n_visible;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
@@ -246,7 +116,9 @@ gtk_filter_list_model_get_item (GListModel *list,
|
||||
break;
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
gtk_filter_list_model_get_nth_filtered (self->items, position, &unfiltered);
|
||||
unfiltered = gtk_bitset_get_nth (self->matches, position);
|
||||
if (unfiltered == 0 && position >= gtk_bitset_get_size (self->matches))
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -268,8 +140,8 @@ G_DEFINE_TYPE_WITH_CODE (GtkFilterListModel, gtk_filter_list_model, G_TYPE_OBJEC
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_filter_list_model_model_init))
|
||||
|
||||
static gboolean
|
||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
guint position)
|
||||
gtk_filter_list_model_run_filter_on_item (GtkFilterListModel *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean visible;
|
||||
@@ -284,26 +156,120 @@ gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
return visible;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_filter_list_model_add_items (GtkFilterListModel *self,
|
||||
FilterNode *after,
|
||||
guint position,
|
||||
guint n_items)
|
||||
static void
|
||||
gtk_filter_list_model_run_filter (GtkFilterListModel *self,
|
||||
guint n_steps)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, n_visible;
|
||||
GtkBitsetIter iter;
|
||||
guint i, pos;
|
||||
gboolean more;
|
||||
|
||||
n_visible = 0;
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
if (self->pending == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0, more = gtk_bitset_iter_init_first (&iter, self->pending, &pos);
|
||||
i < n_steps && more;
|
||||
i++, more = gtk_bitset_iter_next (&iter, &pos))
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->visible = gtk_filter_list_model_run_filter (self, position + i);
|
||||
if (node->visible)
|
||||
n_visible++;
|
||||
if (gtk_filter_list_model_run_filter_on_item (self, pos))
|
||||
gtk_bitset_add (self->matches, pos);
|
||||
}
|
||||
|
||||
return n_visible;
|
||||
if (more)
|
||||
gtk_bitset_remove_range_closed (self->pending, 0, pos);
|
||||
else
|
||||
g_clear_pointer (&self->pending, gtk_bitset_unref);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_stop_filtering (GtkFilterListModel *self)
|
||||
{
|
||||
gboolean notify_pending = self->pending != NULL;
|
||||
|
||||
g_clear_pointer (&self->pending, gtk_bitset_unref);
|
||||
g_clear_handle_id (&self->pending_cb, g_source_remove);
|
||||
|
||||
if (notify_pending)
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (GtkFilterListModel *self,
|
||||
GtkBitset *old)
|
||||
{
|
||||
GtkBitset *changes;
|
||||
|
||||
changes = gtk_bitset_copy (self->matches);
|
||||
gtk_bitset_difference (changes, old);
|
||||
if (!gtk_bitset_is_empty (changes))
|
||||
{
|
||||
guint min, max;
|
||||
|
||||
min = gtk_bitset_get_minimum (changes);
|
||||
max = gtk_bitset_get_maximum (changes);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
min > 0 ? gtk_bitset_get_size_in_range (self->matches, 0, min - 1) : 0,
|
||||
gtk_bitset_get_size_in_range (old, min, max),
|
||||
gtk_bitset_get_size_in_range (self->matches, min, max));
|
||||
}
|
||||
gtk_bitset_unref (changes);
|
||||
gtk_bitset_unref (old);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_filter_list_model_run_filter_cb (gpointer data)
|
||||
{
|
||||
GtkFilterListModel *self = data;
|
||||
GtkBitset *old;
|
||||
|
||||
old = gtk_bitset_copy (self->matches);
|
||||
gtk_filter_list_model_run_filter (self, 512);
|
||||
|
||||
if (self->pending == NULL)
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
/* NB: bitset is (transfer full) */
|
||||
static void
|
||||
gtk_filter_list_model_start_filtering (GtkFilterListModel *self,
|
||||
GtkBitset *items)
|
||||
{
|
||||
if (self->pending)
|
||||
{
|
||||
gtk_bitset_union (self->pending, items);
|
||||
gtk_bitset_unref (items);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gtk_bitset_is_empty (items))
|
||||
{
|
||||
gtk_bitset_unref (items);
|
||||
return;
|
||||
}
|
||||
|
||||
self->pending = items;
|
||||
|
||||
if (!self->incremental)
|
||||
{
|
||||
gtk_filter_list_model_run_filter (self, G_MAXUINT);
|
||||
g_assert (self->pending == NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PENDING]);
|
||||
g_assert (self->pending_cb == 0);
|
||||
self->pending_cb = g_idle_add (gtk_filter_list_model_run_filter_cb, self);
|
||||
g_source_set_name_by_id (self->pending_cb, "[gtk] gtk_filter_list_model_run_filter_cb");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -313,8 +279,7 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
||||
guint added,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, filter_position, filter_removed, filter_added;
|
||||
guint filter_removed, filter_added;
|
||||
|
||||
switch (self->strictness)
|
||||
{
|
||||
@@ -332,22 +297,27 @@ gtk_filter_list_model_items_changed_cb (GListModel *model,
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
node = gtk_filter_list_model_get_nth (self->items, position, &filter_position);
|
||||
if (removed > 0)
|
||||
filter_removed = gtk_bitset_get_size_in_range (self->matches, position, position + removed - 1);
|
||||
else
|
||||
filter_removed = 0;
|
||||
|
||||
filter_removed = 0;
|
||||
for (i = 0; i < removed; i++)
|
||||
gtk_bitset_splice (self->matches, position, removed, added);
|
||||
if (self->pending)
|
||||
gtk_bitset_splice (self->pending, position, removed, added);
|
||||
|
||||
if (added > 0)
|
||||
{
|
||||
FilterNode *next = gtk_rb_tree_node_get_next (node);
|
||||
if (node->visible)
|
||||
filter_removed++;
|
||||
gtk_rb_tree_remove (self->items, node);
|
||||
node = next;
|
||||
gtk_filter_list_model_start_filtering (self, gtk_bitset_new_range (position, added));
|
||||
filter_added = gtk_bitset_get_size_in_range (self->matches, position, position + added - 1);
|
||||
}
|
||||
|
||||
filter_added = gtk_filter_list_model_add_items (self, node, position, added);
|
||||
else
|
||||
filter_added = 0;
|
||||
|
||||
if (filter_removed > 0 || filter_added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), filter_position, filter_removed, filter_added);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
position > 0 ? gtk_bitset_get_size_in_range (self->matches, 0, position - 1) : 0,
|
||||
filter_removed, filter_added);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -364,8 +334,8 @@ gtk_filter_list_model_set_property (GObject *object,
|
||||
gtk_filter_list_model_set_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
case PROP_INCREMENTAL:
|
||||
gtk_filter_list_model_set_incremental (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
@@ -392,14 +362,18 @@ gtk_filter_list_model_get_property (GObject *object,
|
||||
g_value_set_object (value, self->filter);
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
case PROP_INCREMENTAL:
|
||||
g_value_set_boolean (value, self->incremental);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_PENDING:
|
||||
g_value_set_uint (value, gtk_filter_list_model_get_pending (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -412,109 +386,16 @@ gtk_filter_list_model_clear_model (GtkFilterListModel *self)
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_filter_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
if (self->items)
|
||||
gtk_rb_tree_remove_all (self->items);
|
||||
}
|
||||
|
||||
/*<private>
|
||||
* gtk_filter_list_model_find_filtered:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @start: (out) (caller-allocates): number of unfiltered items
|
||||
* at start of list
|
||||
* @end: (out) (caller-allocates): number of unfiltered items
|
||||
* at end of list
|
||||
* @n_items: (out) (caller-allocates): number of unfiltered items in
|
||||
* list
|
||||
*
|
||||
* Checks if elements in self->items are filtered out and returns
|
||||
* the range that they occupy.
|
||||
* This function is intended to be used for GListModel::items-changed
|
||||
* emissions, so it is called in an intermediate state for @self.
|
||||
*
|
||||
* Returns: %TRUE if elements are filtered out, %FALSE if none are
|
||||
**/
|
||||
static gboolean
|
||||
gtk_filter_list_model_find_filtered (GtkFilterListModel *self,
|
||||
guint *start,
|
||||
guint *end,
|
||||
guint *n_items)
|
||||
{
|
||||
FilterNode *root, *node, *tmp;
|
||||
FilterAugment *aug;
|
||||
|
||||
if (self->items == NULL || self->model == NULL)
|
||||
return FALSE;
|
||||
|
||||
root = gtk_rb_tree_get_root (self->items);
|
||||
if (root == NULL)
|
||||
return FALSE; /* empty parent model */
|
||||
|
||||
aug = gtk_rb_tree_get_augment (self->items, root);
|
||||
if (aug->n_items == aug->n_visible)
|
||||
return FALSE; /* all items visible */
|
||||
|
||||
/* find first filtered */
|
||||
*start = 0;
|
||||
*end = 0;
|
||||
*n_items = aug->n_visible;
|
||||
|
||||
node = root;
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_left (node);
|
||||
if (tmp)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
||||
if (aug->n_visible < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
*start += aug->n_items;
|
||||
}
|
||||
|
||||
if (!node->visible)
|
||||
break;
|
||||
|
||||
(*start)++;
|
||||
|
||||
node = gtk_rb_tree_node_get_right (node);
|
||||
}
|
||||
|
||||
/* find last filtered by doing everything the opposite way */
|
||||
node = root;
|
||||
while (node)
|
||||
{
|
||||
tmp = gtk_rb_tree_node_get_right (node);
|
||||
if (tmp)
|
||||
{
|
||||
aug = gtk_rb_tree_get_augment (self->items, tmp);
|
||||
if (aug->n_visible < aug->n_items)
|
||||
{
|
||||
node = tmp;
|
||||
continue;
|
||||
}
|
||||
*end += aug->n_items;
|
||||
}
|
||||
|
||||
if (!node->visible)
|
||||
break;
|
||||
|
||||
(*end)++;
|
||||
|
||||
node = gtk_rb_tree_node_get_left (node);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
if (self->matches)
|
||||
gtk_bitset_remove_all (self->matches);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self);
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self,
|
||||
GtkFilterChange change)
|
||||
{
|
||||
GtkFilterMatch new_strictness;
|
||||
|
||||
@@ -532,8 +413,9 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
guint n_before = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
self->strictness = new_strictness;
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
if (n_before > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_before, 0);
|
||||
}
|
||||
@@ -553,16 +435,35 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
{
|
||||
guint start, end, n_before, n_after;
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
self->strictness = new_strictness;
|
||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_before))
|
||||
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
start = gtk_bitset_get_minimum (self->matches);
|
||||
end = gtk_bitset_get_maximum (self->matches);
|
||||
|
||||
n_before = gtk_bitset_get_size (self->matches);
|
||||
if (n_before == n_after)
|
||||
{
|
||||
n_after = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
GtkBitset *inverse;
|
||||
|
||||
inverse = gtk_bitset_new_range (0, n_after);
|
||||
gtk_bitset_subtract (inverse, self->matches);
|
||||
/* otherwise all items would be visible */
|
||||
g_assert (!gtk_bitset_is_empty (inverse));
|
||||
|
||||
/* find first filtered */
|
||||
start = gtk_bitset_get_minimum (inverse);
|
||||
end = n_after - gtk_bitset_get_maximum (inverse) - 1;
|
||||
|
||||
gtk_bitset_unref (inverse);
|
||||
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -574,40 +475,44 @@ gtk_filter_list_model_update_strictness_and_refilter (GtkFilterListModel *self)
|
||||
break;
|
||||
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
switch (self->strictness)
|
||||
{
|
||||
case GTK_FILTER_MATCH_NONE:
|
||||
{
|
||||
GtkBitset *old, *pending;
|
||||
|
||||
if (self->matches == NULL)
|
||||
{
|
||||
guint n_after;
|
||||
self->strictness = new_strictness;
|
||||
self->items = gtk_rb_tree_new (FilterNode,
|
||||
FilterAugment,
|
||||
gtk_filter_list_model_augment,
|
||||
NULL, NULL);
|
||||
n_after = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (self->model));
|
||||
if (n_after > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, 0, n_after);
|
||||
if (self->strictness == GTK_FILTER_MATCH_ALL)
|
||||
old = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
else
|
||||
old = gtk_bitset_new_empty ();
|
||||
}
|
||||
break;
|
||||
case GTK_FILTER_MATCH_ALL:
|
||||
else
|
||||
{
|
||||
guint start, end, n_before, n_after;
|
||||
self->strictness = new_strictness;
|
||||
self->items = gtk_rb_tree_new (FilterNode,
|
||||
FilterAugment,
|
||||
gtk_filter_list_model_augment,
|
||||
NULL, NULL);
|
||||
n_before = g_list_model_get_n_items (self->model);
|
||||
gtk_filter_list_model_add_items (self, NULL, 0, n_before);
|
||||
if (gtk_filter_list_model_find_filtered (self, &start, &end, &n_after))
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_before - end - start, n_after - end - start);
|
||||
old = self->matches;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case GTK_FILTER_MATCH_SOME:
|
||||
gtk_filter_list_model_refilter (self);
|
||||
break;
|
||||
}
|
||||
self->strictness = new_strictness;
|
||||
switch (change)
|
||||
{
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case GTK_FILTER_CHANGE_DIFFERENT:
|
||||
self->matches = gtk_bitset_new_empty ();
|
||||
pending = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
break;
|
||||
case GTK_FILTER_CHANGE_LESS_STRICT:
|
||||
self->matches = gtk_bitset_copy (old);
|
||||
pending = gtk_bitset_new_range (0, g_list_model_get_n_items (self->model));
|
||||
gtk_bitset_subtract (pending, self->matches);
|
||||
break;
|
||||
case GTK_FILTER_CHANGE_MORE_STRICT:
|
||||
self->matches = gtk_bitset_new_empty ();
|
||||
pending = gtk_bitset_copy (old);
|
||||
break;
|
||||
}
|
||||
gtk_filter_list_model_start_filtering (self, pending);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,7 +521,7 @@ gtk_filter_list_model_filter_changed_cb (GtkFilter *filter,
|
||||
GtkFilterChange change,
|
||||
GtkFilterListModel *self)
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, change);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -636,7 +541,7 @@ gtk_filter_list_model_dispose (GObject *object)
|
||||
|
||||
gtk_filter_list_model_clear_model (self);
|
||||
gtk_filter_list_model_clear_filter (self);
|
||||
g_clear_pointer (&self->items, gtk_rb_tree_unref);
|
||||
g_clear_pointer (&self->matches, gtk_bitset_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_filter_list_model_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -663,16 +568,16 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:item-type:
|
||||
* GtkFilterListModel:incremental:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
* If the model should filter items incrementally
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
properties[PROP_INCREMENTAL] =
|
||||
g_param_spec_boolean ("incremental",
|
||||
P_("Incremental"),
|
||||
P_("Filer items incrementally"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:model:
|
||||
@@ -686,6 +591,18 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:pending:
|
||||
*
|
||||
* Number of items not yet filtered
|
||||
*/
|
||||
properties[PROP_PENDING] =
|
||||
g_param_spec_uint ("pending",
|
||||
P_("Pending"),
|
||||
P_("Number of items not yet filtered"),
|
||||
0, G_MAXUINT, 0,
|
||||
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
@@ -697,7 +614,7 @@ gtk_filter_list_model_init (GtkFilterListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new:
|
||||
* @model: the model to sort
|
||||
* @model: (allow-none): the model to sort
|
||||
* @filter: (allow-none): filter or %NULL to not filter items
|
||||
*
|
||||
* Creates a new #GtkFilterListModel that will filter @model using the given
|
||||
@@ -711,10 +628,10 @@ gtk_filter_list_model_new (GListModel *model,
|
||||
{
|
||||
GtkFilterListModel *result;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (filter == NULL || GTK_IS_FILTER (filter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"filter", filter,
|
||||
NULL);
|
||||
@@ -722,26 +639,6 @@ gtk_filter_list_model_new (GListModel *model,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_new_for_type:
|
||||
* @item_type: the type of the items that will be returned
|
||||
*
|
||||
* Creates a new empty filter list model set up to return items of type @item_type.
|
||||
* It is up to the application to set a proper filter and model to ensure
|
||||
* the item type is matched.
|
||||
*
|
||||
* Returns: a new #GtkFilterListModel
|
||||
**/
|
||||
GtkFilterListModel *
|
||||
gtk_filter_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_FILTER_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_set_filter:
|
||||
* @self: a #GtkFilterListModel
|
||||
@@ -769,7 +666,7 @@ gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILTER]);
|
||||
@@ -828,13 +725,18 @@ gtk_filter_list_model_set_model (GtkFilterListModel *self,
|
||||
if (removed == 0)
|
||||
{
|
||||
self->strictness = GTK_FILTER_MATCH_NONE;
|
||||
gtk_filter_list_model_update_strictness_and_refilter (self);
|
||||
gtk_filter_list_model_refilter (self, GTK_FILTER_CHANGE_LESS_STRICT);
|
||||
added = 0;
|
||||
}
|
||||
else if (self->items)
|
||||
added = gtk_filter_list_model_add_items (self, NULL, 0, g_list_model_get_n_items (model));
|
||||
else if (self->matches)
|
||||
{
|
||||
gtk_filter_list_model_start_filtering (self, gtk_bitset_new_range (0, g_list_model_get_n_items (model)));
|
||||
added = gtk_bitset_get_size (self->matches);
|
||||
}
|
||||
else
|
||||
added = g_list_model_get_n_items (model);
|
||||
{
|
||||
added = g_list_model_get_n_items (model);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -864,54 +766,89 @@ gtk_filter_list_model_get_model (GtkFilterListModel *self)
|
||||
return self->model;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_filter_list_model_refilter (GtkFilterListModel *self)
|
||||
/**
|
||||
* gtk_filter_list_model_set_incremental:
|
||||
* @self: a #GtkFilterListModel
|
||||
* @incremental: %TRUE to enable incremental filtering
|
||||
*
|
||||
* When incremental filtering is enabled, the filterlistmodel will not run
|
||||
* filters immediately, but will instead queue an idle handler that
|
||||
* incrementally filters the items and adds them to the list. This of course
|
||||
* means that items are not instantly added to the list, but only appear
|
||||
* incrementally.
|
||||
*
|
||||
* When your filter blocks the UI while filtering, you might consider
|
||||
* turning this on. Depending on your model and filters, this may become
|
||||
* interesting around 10,000 to 100,000 items.
|
||||
*
|
||||
* By default, incremental filtering is disabled.
|
||||
**/
|
||||
void
|
||||
gtk_filter_list_model_set_incremental (GtkFilterListModel *self,
|
||||
gboolean incremental)
|
||||
{
|
||||
FilterNode *node;
|
||||
guint i, first_change, last_change;
|
||||
guint n_is_visible, n_was_visible;
|
||||
gboolean visible;
|
||||
|
||||
g_return_if_fail (GTK_IS_FILTER_LIST_MODEL (self));
|
||||
|
||||
if (self->items == NULL || self->model == NULL)
|
||||
|
||||
if (self->incremental == incremental)
|
||||
return;
|
||||
|
||||
first_change = G_MAXUINT;
|
||||
last_change = 0;
|
||||
n_is_visible = 0;
|
||||
n_was_visible = 0;
|
||||
for (i = 0, node = gtk_rb_tree_get_first (self->items);
|
||||
node != NULL;
|
||||
i++, node = gtk_rb_tree_node_get_next (node))
|
||||
{
|
||||
visible = gtk_filter_list_model_run_filter (self, i);
|
||||
if (visible == node->visible)
|
||||
{
|
||||
if (visible)
|
||||
{
|
||||
n_is_visible++;
|
||||
n_was_visible++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
self->incremental = incremental;
|
||||
|
||||
node->visible = visible;
|
||||
gtk_rb_tree_node_mark_dirty (node);
|
||||
first_change = MIN (n_is_visible, first_change);
|
||||
if (visible)
|
||||
n_is_visible++;
|
||||
else
|
||||
n_was_visible++;
|
||||
last_change = MAX (n_is_visible, last_change);
|
||||
if (!incremental)
|
||||
{
|
||||
GtkBitset *old;
|
||||
gtk_filter_list_model_run_filter (self, G_MAXUINT);
|
||||
|
||||
old = gtk_bitset_copy (self->matches);
|
||||
gtk_filter_list_model_run_filter (self, 512);
|
||||
|
||||
gtk_filter_list_model_stop_filtering (self);
|
||||
|
||||
gtk_filter_list_model_emit_items_changed_for_changes (self, old);
|
||||
}
|
||||
|
||||
if (first_change <= last_change)
|
||||
{
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
first_change,
|
||||
last_change - first_change + n_was_visible - n_is_visible,
|
||||
last_change - first_change);
|
||||
}
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_INCREMENTAL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_incremental:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Returns whether incremental filtering was enabled via
|
||||
* gtk_filter_list_model_set_incremental().
|
||||
*
|
||||
* Returns: %TRUE if incremental filtering is enabled
|
||||
**/
|
||||
gboolean
|
||||
gtk_filter_list_model_get_incremental (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE);
|
||||
|
||||
return self->incremental;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_filter_list_model_get_pending:
|
||||
* @self: a #GtkFilterListModel
|
||||
*
|
||||
* Returns the number of items that have not been filtered yet.
|
||||
*
|
||||
* When incremental filtering is not enabled, this always returns 0.
|
||||
*
|
||||
* You can use this value to check if @self is busy filtering by
|
||||
* comparing the return value to 0 or you can compute the percentage
|
||||
* of the filter remaining by dividing the return value by
|
||||
* g_list_model_get_n_items(gtk_filter_list_model_get_model (self)).
|
||||
*
|
||||
* Returns: The number of items not yet filtered
|
||||
**/
|
||||
guint
|
||||
gtk_filter_list_model_get_pending (GtkFilterListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_FILTER_LIST_MODEL (self), FALSE);
|
||||
|
||||
if (self->pending == NULL)
|
||||
return 0;
|
||||
|
||||
return gtk_bitset_get_size (self->pending);
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ G_DECLARE_FINAL_TYPE (GtkFilterListModel, gtk_filter_list_model, GTK, FILTER_LIS
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new (GListModel *model,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilterListModel * gtk_filter_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_filter (GtkFilterListModel *self,
|
||||
@@ -52,6 +50,14 @@ void gtk_filter_list_model_set_model (GtkFilterListMo
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_filter_list_model_get_model (GtkFilterListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_filter_list_model_set_incremental (GtkFilterListModel *self,
|
||||
gboolean incremental);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_filter_list_model_get_incremental (GtkFilterListModel *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_filter_list_model_get_pending (GtkFilterListModel *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
@@ -64,7 +63,6 @@ struct _GtkFlattenListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkRbTree *items; /* NULL if model == NULL */
|
||||
};
|
||||
@@ -157,9 +155,7 @@ gtk_flatten_list_model_get_nth_model (GtkRbTree *tree,
|
||||
static GType
|
||||
gtk_flatten_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -299,7 +295,6 @@ gtk_flatten_list_model_add_items (GtkFlattenListModel *self,
|
||||
{
|
||||
node = gtk_rb_tree_insert_before (self->items, after);
|
||||
node->model = g_list_model_get_item (self->model, position + i);
|
||||
g_warn_if_fail (g_type_is_a (g_list_model_get_item_type (node->model), self->item_type));
|
||||
g_signal_connect (node->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_flatten_list_model_items_changed_cb),
|
||||
@@ -321,10 +316,6 @@ gtk_flatten_list_model_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_flatten_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -345,10 +336,6 @@ gtk_flatten_list_model_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
@@ -416,18 +403,6 @@ gtk_flatten_list_model_class_init (GtkFlattenListModelClass *class)
|
||||
gobject_class->get_property = gtk_flatten_list_model_get_property;
|
||||
gobject_class->dispose = gtk_flatten_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFlattenListModel:model:
|
||||
*
|
||||
@@ -450,26 +425,20 @@ gtk_flatten_list_model_init (GtkFlattenListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_flatten_list_model_new:
|
||||
* @item_type: The type of items in the to-be-flattened models
|
||||
* @model: (nullable) (transfer none): the item to be flattened
|
||||
* @model: (nullable) (transfer none): the model to be flattened
|
||||
*
|
||||
* Creates a new #GtkFlattenListModel that flattens @list. The
|
||||
* models returned by @model must conform to the given @item_type,
|
||||
* either by having an identical type or a subtype.
|
||||
* Creates a new #GtkFlattenListModel that flattens @list.
|
||||
*
|
||||
* Returns: a new #GtkFlattenListModel
|
||||
**/
|
||||
GtkFlattenListModel *
|
||||
gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model)
|
||||
gtk_flatten_list_model_new (GListModel *model)
|
||||
{
|
||||
GtkFlattenListModel *result;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_FLATTEN_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
"model", model,
|
||||
NULL);
|
||||
|
||||
@@ -481,8 +450,7 @@ gtk_flatten_list_model_new (GType item_type,
|
||||
* @self: a #GtkFlattenListModel
|
||||
* @model: (nullable) (transfer none): the new model or %NULL
|
||||
*
|
||||
* Sets a new model to be flattened. The model must contain items of
|
||||
* #GListModel that conform to the item type of @self.
|
||||
* Sets a new model to be flattened.
|
||||
**/
|
||||
void
|
||||
gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
@@ -492,10 +460,6 @@ gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
|
||||
g_return_if_fail (GTK_IS_FLATTEN_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
if (model)
|
||||
{
|
||||
g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), G_TYPE_LIST_MODEL));
|
||||
}
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
@@ -36,8 +36,7 @@ GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkFlattenListModel, gtk_flatten_list_model, GTK, FLATTEN_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFlattenListModel * gtk_flatten_list_model_new (GType item_type,
|
||||
GListModel *model);
|
||||
GtkFlattenListModel * gtk_flatten_list_model_new (GListModel *model);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_flatten_list_model_set_model (GtkFlattenListModel *self,
|
||||
|
||||
@@ -784,7 +784,7 @@ update_fontlist (GtkFontChooserWidget *self)
|
||||
if ((self->level & GTK_FONT_CHOOSER_LEVEL_STYLE) == 0)
|
||||
model = g_object_ref (G_LIST_MODEL (fontmap));
|
||||
else
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (PANGO_TYPE_FONT_FACE, G_LIST_MODEL (fontmap)));
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (fontmap)));
|
||||
gtk_filter_list_model_set_model (self->filter_model, model);
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
+30
-25
@@ -55,6 +55,14 @@
|
||||
#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
|
||||
#define GTK_VECTOR_PREALLOC 16
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkicontheme
|
||||
* @Short_description: Looking up icons by name
|
||||
@@ -2276,13 +2284,13 @@ real_choose_icon (GtkIconTheme *self,
|
||||
}
|
||||
|
||||
static void
|
||||
icon_name_list_add_icon (GPtrArray *icons,
|
||||
const gchar *dir_suffix,
|
||||
gchar *icon_name)
|
||||
icon_name_list_add_icon (GtkStrvBuilder *icons,
|
||||
const gchar *dir_suffix,
|
||||
gchar *icon_name)
|
||||
{
|
||||
if (dir_suffix)
|
||||
g_ptr_array_add (icons, g_strconcat (icon_name, dir_suffix, NULL));
|
||||
g_ptr_array_add (icons, icon_name);
|
||||
gtk_strv_builder_append (icons, g_strconcat (icon_name, dir_suffix, NULL));
|
||||
gtk_strv_builder_append (icons, icon_name);
|
||||
}
|
||||
|
||||
static GtkIconPaintable *
|
||||
@@ -2296,7 +2304,7 @@ choose_icon (GtkIconTheme *self,
|
||||
{
|
||||
gboolean has_regular = FALSE, has_symbolic = FALSE;
|
||||
GtkIconPaintable *icon;
|
||||
GPtrArray *new_names;
|
||||
GtkStrvBuilder new_names;
|
||||
const gchar *dir_suffix;
|
||||
guint i;
|
||||
|
||||
@@ -2327,73 +2335,70 @@ choose_icon (GtkIconTheme *self,
|
||||
|
||||
if ((flags & GTK_ICON_LOOKUP_FORCE_REGULAR) && has_symbolic)
|
||||
{
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
gtk_strv_builder_init (&new_names);
|
||||
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 gchar **) new_names->pdata,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
}
|
||||
else if ((flags & GTK_ICON_LOOKUP_FORCE_SYMBOLIC) && has_regular)
|
||||
{
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
gtk_strv_builder_init (&new_names);
|
||||
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 gchar **) new_names->pdata,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
}
|
||||
else if (dir_suffix)
|
||||
{
|
||||
new_names = g_ptr_array_new_with_free_func (g_free);
|
||||
gtk_strv_builder_init (&new_names);
|
||||
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 gchar **) new_names->pdata,
|
||||
(const char **) gtk_strv_builder_get_data (&new_names),
|
||||
size,
|
||||
scale,
|
||||
flags & ~(GTK_ICON_LOOKUP_FORCE_REGULAR | GTK_ICON_LOOKUP_FORCE_SYMBOLIC),
|
||||
non_blocking);
|
||||
|
||||
g_ptr_array_free (new_names, TRUE);
|
||||
gtk_strv_builder_clear (&new_names);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+24
-20
@@ -95,7 +95,6 @@
|
||||
#include "gdk/gdk-private.h"
|
||||
#include "gsk/gskprivate.h"
|
||||
#include "gsk/gskrendernodeprivate.h"
|
||||
#include "gtkarrayimplprivate.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
#include <locale.h>
|
||||
@@ -138,6 +137,13 @@
|
||||
#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;
|
||||
@@ -1321,8 +1327,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
double x, y;
|
||||
GtkWidget *prev;
|
||||
gboolean seen_ancestor;
|
||||
GtkArray target_array;
|
||||
GtkWidget *stack_targets[16];
|
||||
GtkWidgetStack target_array;
|
||||
int i;
|
||||
|
||||
if (old_target == new_target)
|
||||
@@ -1376,19 +1381,19 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
widget = _gtk_widget_get_parent (widget);
|
||||
}
|
||||
|
||||
gtk_array_init (&target_array, (void**)stack_targets, 16);
|
||||
gtk_widget_stack_init (&target_array);
|
||||
for (widget = new_target; widget; widget = _gtk_widget_get_parent (widget))
|
||||
gtk_array_add (&target_array, widget);
|
||||
gtk_widget_stack_append (&target_array, g_object_ref (widget));
|
||||
|
||||
crossing.direction = GTK_CROSSING_IN;
|
||||
|
||||
seen_ancestor = FALSE;
|
||||
for (i = (int)target_array.len - 1; i >= 0; i--)
|
||||
for (i = gtk_widget_stack_get_size (&target_array) - 1; i >= 0; i--)
|
||||
{
|
||||
widget = gtk_array_index (&target_array, i);
|
||||
widget = gtk_widget_stack_get (&target_array, i);
|
||||
|
||||
if (i < (int)target_array.len - 1)
|
||||
crossing.new_descendent = gtk_array_index (&target_array, i + 1);
|
||||
if (i < gtk_widget_stack_get_size (&target_array) - 1)
|
||||
crossing.new_descendent = gtk_widget_stack_get (&target_array, i + 1);
|
||||
else
|
||||
crossing.new_descendent = NULL;
|
||||
|
||||
@@ -1417,7 +1422,7 @@ gtk_synthesize_crossing_events (GtkRoot *toplevel,
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
|
||||
}
|
||||
|
||||
gtk_array_free (&target_array, NULL);
|
||||
gtk_widget_stack_clear (&target_array);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
@@ -1994,13 +1999,12 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
{
|
||||
gint handled_event = FALSE;
|
||||
GtkWidget *target = widget;
|
||||
GtkArray widget_array;
|
||||
GtkWidget *stack_widgets[16];
|
||||
GtkWidgetStack widget_array;
|
||||
int i;
|
||||
|
||||
/* First, propagate event down */
|
||||
gtk_array_init (&widget_array, (void**)stack_widgets, 16);
|
||||
gtk_array_add (&widget_array, g_object_ref (widget));
|
||||
gtk_widget_stack_init (&widget_array);
|
||||
gtk_widget_stack_append (&widget_array, g_object_ref (widget));
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -2008,16 +2012,16 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
if (!widget)
|
||||
break;
|
||||
|
||||
gtk_array_add (&widget_array, g_object_ref (widget));
|
||||
gtk_widget_stack_append (&widget_array, g_object_ref (widget));
|
||||
|
||||
if (widget == topmost)
|
||||
break;
|
||||
}
|
||||
|
||||
i = widget_array.len - 1;
|
||||
i = gtk_widget_stack_get_size (&widget_array) - 1;
|
||||
for (;;)
|
||||
{
|
||||
widget = gtk_array_index (&widget_array, i);
|
||||
widget = gtk_widget_stack_get (&widget_array, i);
|
||||
|
||||
if (!_gtk_widget_is_sensitive (widget))
|
||||
{
|
||||
@@ -2050,9 +2054,9 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
* parents can see the button and motion
|
||||
* events of the children.
|
||||
*/
|
||||
for (i = 0; i < widget_array.len; i++)
|
||||
for (i = 0; i < gtk_widget_stack_get_size (&widget_array); i++)
|
||||
{
|
||||
widget = gtk_array_index (&widget_array, i);
|
||||
widget = gtk_widget_stack_get (&widget_array, i);
|
||||
|
||||
/* Scroll events are special cased here because it
|
||||
* feels wrong when scrolling a GtkViewport, say,
|
||||
@@ -2071,7 +2075,7 @@ gtk_propagate_event_internal (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
gtk_array_free (&widget_array, g_object_unref);
|
||||
gtk_widget_stack_clear (&widget_array);
|
||||
return handled_event;
|
||||
}
|
||||
|
||||
|
||||
+2
-35
@@ -63,7 +63,6 @@
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_HAS_MAP,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
@@ -86,7 +85,6 @@ struct _GtkMapListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkMapListModelMapFunc map_func;
|
||||
gpointer user_data;
|
||||
@@ -145,9 +143,7 @@ gtk_map_list_model_get_nth (GtkRbTree *tree,
|
||||
static GType
|
||||
gtk_map_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkMapListModel *self = GTK_MAP_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -199,11 +195,6 @@ gtk_map_list_model_get_item (GListModel *list,
|
||||
}
|
||||
|
||||
node->item = self->map_func (g_list_model_get_item (self->model, position), self->user_data);
|
||||
if (!G_TYPE_CHECK_INSTANCE_TYPE (node->item, self->item_type))
|
||||
{
|
||||
g_critical ("Map function returned a %s, but it is not a subtype of the model's type %s",
|
||||
G_OBJECT_TYPE_NAME (node->item), g_type_name (self->item_type));
|
||||
}
|
||||
g_object_add_weak_pointer (node->item, &node->item);
|
||||
|
||||
return node->item;
|
||||
@@ -293,10 +284,6 @@ gtk_map_list_model_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_map_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -321,10 +308,6 @@ gtk_map_list_model_get_property (GObject *object,
|
||||
g_value_set_boolean (value, self->items != NULL);
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
@@ -382,18 +365,6 @@ gtk_map_list_model_class_init (GtkMapListModelClass *class)
|
||||
FALSE,
|
||||
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkMapListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkMapListModel:model:
|
||||
*
|
||||
@@ -441,7 +412,6 @@ gtk_map_list_model_augment (GtkRbTree *map,
|
||||
|
||||
/**
|
||||
* gtk_map_list_model_new:
|
||||
* @item_type: the #GType to use as the model's item type
|
||||
* @model: (allow-none): The model to map or %NULL for none
|
||||
* @map_func: (allow-none): map function or %NULL to not map items
|
||||
* @user_data: (closure): user data passed to @map_func
|
||||
@@ -452,19 +422,16 @@ gtk_map_list_model_augment (GtkRbTree *map,
|
||||
* Returns: a new #GtkMapListModel
|
||||
**/
|
||||
GtkMapListModel *
|
||||
gtk_map_list_model_new (GType item_type,
|
||||
GListModel *model,
|
||||
gtk_map_list_model_new (GListModel *model,
|
||||
GtkMapListModelMapFunc map_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy)
|
||||
{
|
||||
GtkMapListModel *result;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_MAP_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
"model", model,
|
||||
NULL);
|
||||
|
||||
|
||||
@@ -53,8 +53,7 @@ G_DECLARE_FINAL_TYPE (GtkMapListModel, gtk_map_list_model, GTK, MAP_LIST_MODEL,
|
||||
typedef gpointer (* GtkMapListModelMapFunc) (gpointer item, gpointer user_data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkMapListModel * gtk_map_list_model_new (GType item_type,
|
||||
GListModel *model,
|
||||
GtkMapListModel * gtk_map_list_model_new (GListModel *model,
|
||||
GtkMapListModelMapFunc map_func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy);
|
||||
|
||||
+57
-12
@@ -62,9 +62,7 @@ static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static GType
|
||||
gtk_multi_selection_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -72,6 +70,9 @@ gtk_multi_selection_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
@@ -81,6 +82,9 @@ gtk_multi_selection_get_item (GListModel *list,
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
@@ -174,7 +178,7 @@ gtk_multi_selection_set_selection (GtkSelectionModel *model,
|
||||
max = gtk_bitset_get_maximum (changes);
|
||||
|
||||
/* sanity check */
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
n_items = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
if (max >= n_items)
|
||||
{
|
||||
gtk_bitset_remove_range_closed (changes, n_items, max);
|
||||
@@ -218,7 +222,7 @@ gtk_multi_selection_items_changed_cb (GListModel *model,
|
||||
GHashTable *pending = NULL;
|
||||
guint i;
|
||||
|
||||
gtk_bitset_slice (self->selected, position, removed, added);
|
||||
gtk_bitset_splice (self->selected, position, removed, added);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->items);
|
||||
while (g_hash_table_iter_next (&iter, &item, &pos_pointer))
|
||||
@@ -291,12 +295,7 @@ gtk_multi_selection_set_property (GObject *object,
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
self->model = g_value_dup_object (value);
|
||||
g_warn_if_fail (self->model != NULL);
|
||||
g_signal_connect (self->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_multi_selection_items_changed_cb),
|
||||
self);
|
||||
gtk_multi_selection_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -357,7 +356,7 @@ gtk_multi_selection_class_init (GtkMultiSelectionClass *klass)
|
||||
P_("Model"),
|
||||
P_("List managed by this selection"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
@@ -402,3 +401,49 @@ gtk_multi_selection_get_model (GtkMultiSelection *self)
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_multi_selection_set_model:
|
||||
* @self: a #GtkMultiSelection
|
||||
* @model: (allow-none): A #GListModel to wrap
|
||||
*
|
||||
* Sets the model that @self should wrap. If @model is %NULL, @self
|
||||
* will be empty.
|
||||
**/
|
||||
void
|
||||
gtk_multi_selection_set_model (GtkMultiSelection *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint n_items_before;
|
||||
|
||||
g_return_if_fail (GTK_IS_MULTI_SELECTION (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
gtk_multi_selection_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (self->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_multi_selection_items_changed_cb),
|
||||
self);
|
||||
gtk_multi_selection_items_changed_cb (self->model,
|
||||
0,
|
||||
n_items_before,
|
||||
g_list_model_get_n_items (model),
|
||||
self);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_bitset_remove_all (self->selected);
|
||||
g_hash_table_remove_all (self->items);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, 0);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,9 @@ GListModel * gtk_multi_selection_new (GListModel *mo
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_multi_selection_get_model (GtkMultiSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_multi_selection_set_model (GtkMultiSelection *self,
|
||||
GListModel *model);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+50
-12
@@ -60,9 +60,7 @@ static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static GType
|
||||
gtk_no_selection_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkNoSelection *self = GTK_NO_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -70,15 +68,21 @@ gtk_no_selection_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkNoSelection *self = GTK_NO_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_no_selection_get_item (GListModel *list,
|
||||
guint position)
|
||||
guint position)
|
||||
{
|
||||
GtkNoSelection *self = GTK_NO_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
@@ -132,9 +136,9 @@ gtk_no_selection_clear_model (GtkNoSelection *self)
|
||||
|
||||
static void
|
||||
gtk_no_selection_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkNoSelection *self = GTK_NO_SELECTION (object);
|
||||
@@ -142,10 +146,7 @@ gtk_no_selection_set_property (GObject *object,
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
gtk_no_selection_clear_model (self);
|
||||
self->model = g_value_dup_object (value);
|
||||
g_signal_connect_swapped (self->model, "items-changed",
|
||||
G_CALLBACK (g_list_model_items_changed), self);
|
||||
gtk_no_selection_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -203,7 +204,7 @@ gtk_no_selection_class_init (GtkNoSelectionClass *klass)
|
||||
P_("The model"),
|
||||
P_("The model being managed"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
@@ -247,3 +248,40 @@ gtk_no_selection_get_model (GtkNoSelection *self)
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_no_selection_set_model:
|
||||
* @self: a #GtkNoSelection
|
||||
* @model: (allow-none): A #GListModel to wrap
|
||||
*
|
||||
* Sets the model that @self should wrap. If @model is %NULL, this
|
||||
* model will be empty.
|
||||
**/
|
||||
void
|
||||
gtk_no_selection_set_model (GtkNoSelection *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint n_items_before;
|
||||
|
||||
g_return_if_fail (GTK_IS_NO_SELECTION (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
gtk_no_selection_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect_swapped (self->model, "items-changed",
|
||||
G_CALLBACK (g_list_model_items_changed), self);
|
||||
}
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self),
|
||||
0,
|
||||
n_items_before,
|
||||
model ? g_list_model_get_n_items (self->model) : 0);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ GtkNoSelection * gtk_no_selection_new (GListModel
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_no_selection_get_model (GtkNoSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_no_selection_set_model (GtkNoSelection *self,
|
||||
GListModel *model);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
|
||||
g_list_store_append (store, dialog->page_setup_list);
|
||||
g_list_store_append (store, dialog->custom_paper_list);
|
||||
g_list_store_append (store, dialog->manage_papers_list);
|
||||
paper_size_list = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PAGE_SETUP, G_LIST_MODEL (store)));
|
||||
paper_size_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (store)));
|
||||
gtk_drop_down_set_model (GTK_DROP_DOWN (dialog->paper_size_combo), paper_size_list);
|
||||
g_object_unref (store);
|
||||
g_object_unref (paper_size_list);
|
||||
@@ -321,7 +321,7 @@ gtk_page_setup_unix_dialog_init (GtkPageSetupUnixDialog *dialog)
|
||||
g_list_store_append (printer_list_list, printer_list);
|
||||
g_object_unref (printer_list);
|
||||
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PRINTER, G_LIST_MODEL (printer_list_list)));
|
||||
full_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (printer_list_list)));
|
||||
|
||||
filter = gtk_custom_filter_new (match_func, NULL, NULL);
|
||||
dialog->printer_list = G_LIST_MODEL (gtk_filter_list_model_new (full_list, filter));
|
||||
|
||||
+47
-56
@@ -162,7 +162,7 @@ struct _GtkPlacesSidebar {
|
||||
|
||||
GtkWidget *popover;
|
||||
GtkSidebarRow *context_row;
|
||||
GSList *shortcuts;
|
||||
GListStore *shortcuts;
|
||||
|
||||
GDBusProxy *hostnamed_proxy;
|
||||
GCancellable *hostnamed_cancellable;
|
||||
@@ -709,15 +709,25 @@ file_is_shown (GtkPlacesSidebar *sidebar,
|
||||
return found;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkPlacesSidebar *sidebar;
|
||||
guint position;
|
||||
} ShortcutData;
|
||||
|
||||
static void
|
||||
on_app_shortcuts_query_complete (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPlacesSidebar *sidebar = data;
|
||||
ShortcutData *sdata = data;
|
||||
GtkPlacesSidebar *sidebar = sdata->sidebar;
|
||||
guint pos = sdata->position;
|
||||
GFile *file = G_FILE (source);
|
||||
GFileInfo *info;
|
||||
|
||||
g_free (sdata);
|
||||
|
||||
info = g_file_query_info_finish (file, result, NULL);
|
||||
|
||||
if (info)
|
||||
@@ -726,20 +736,12 @@ on_app_shortcuts_query_complete (GObject *source,
|
||||
gchar *tooltip;
|
||||
const gchar *name;
|
||||
GIcon *start_icon;
|
||||
int pos = 0;
|
||||
|
||||
name = g_file_info_get_display_name (info);
|
||||
start_icon = g_file_info_get_symbolic_icon (info);
|
||||
uri = g_file_get_uri (file);
|
||||
tooltip = g_file_get_parse_name (file);
|
||||
|
||||
/* XXX: we could avoid this by using an ancillary closure
|
||||
* with the index coming from add_application_shortcuts(),
|
||||
* but in terms of algorithmic overhead, the application
|
||||
* shortcuts is not going to be really big
|
||||
*/
|
||||
pos = g_slist_index (sidebar->shortcuts, file);
|
||||
|
||||
add_place (sidebar, PLACES_BUILT_IN,
|
||||
SECTION_COMPUTER,
|
||||
name, start_icon, NULL, uri,
|
||||
@@ -757,11 +759,13 @@ on_app_shortcuts_query_complete (GObject *source,
|
||||
static void
|
||||
add_application_shortcuts (GtkPlacesSidebar *sidebar)
|
||||
{
|
||||
GSList *l;
|
||||
guint i, n;
|
||||
|
||||
for (l = sidebar->shortcuts; l; l = l->next)
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (sidebar->shortcuts));
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GFile *file = l->data;
|
||||
GFile *file = g_list_model_get_item (G_LIST_MODEL (sidebar->shortcuts), i);
|
||||
ShortcutData *data;
|
||||
|
||||
if (!should_show_file (sidebar, file))
|
||||
continue;
|
||||
@@ -769,13 +773,16 @@ add_application_shortcuts (GtkPlacesSidebar *sidebar)
|
||||
if (file_is_shown (sidebar, file))
|
||||
continue;
|
||||
|
||||
data = g_new (ShortcutData, 1);
|
||||
data->sidebar = sidebar;
|
||||
data->position = i;
|
||||
g_file_query_info_async (file,
|
||||
"standard::display-name,standard::symbolic-icon",
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
G_PRIORITY_DEFAULT,
|
||||
sidebar->cancellable,
|
||||
on_app_shortcuts_query_complete,
|
||||
sidebar);
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3748,6 +3755,8 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
|
||||
sidebar->show_recent = TRUE;
|
||||
sidebar->show_desktop = TRUE;
|
||||
|
||||
sidebar->shortcuts = g_list_store_new (G_TYPE_FILE);
|
||||
|
||||
create_volume_monitor (sidebar);
|
||||
|
||||
sidebar->open_flags = GTK_PLACES_OPEN_NORMAL;
|
||||
@@ -4018,9 +4027,7 @@ gtk_places_sidebar_dispose (GObject *object)
|
||||
|
||||
g_clear_object (&sidebar->current_location);
|
||||
g_clear_pointer (&sidebar->rename_uri, g_free);
|
||||
|
||||
g_slist_free_full (sidebar->shortcuts, g_object_unref);
|
||||
sidebar->shortcuts = NULL;
|
||||
g_clear_object (&sidebar->shortcuts);
|
||||
|
||||
#ifdef HAVE_CLOUDPROVIDERS
|
||||
for (l = cloud_providers_collector_get_providers (sidebar->cloud_manager);
|
||||
@@ -4782,24 +4789,6 @@ gtk_places_sidebar_get_show_trash (GtkPlacesSidebar *sidebar)
|
||||
return sidebar->show_trash;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
find_shortcut_link (GtkPlacesSidebar *sidebar,
|
||||
GFile *location)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = sidebar->shortcuts; l; l = l->next)
|
||||
{
|
||||
GFile *shortcut;
|
||||
|
||||
shortcut = G_FILE (l->data);
|
||||
if (g_file_equal (shortcut, location))
|
||||
return l;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_places_sidebar_add_shortcut:
|
||||
* @sidebar: a places sidebar
|
||||
@@ -4823,8 +4812,7 @@ gtk_places_sidebar_add_shortcut (GtkPlacesSidebar *sidebar,
|
||||
g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
|
||||
g_return_if_fail (G_IS_FILE (location));
|
||||
|
||||
g_object_ref (location);
|
||||
sidebar->shortcuts = g_slist_append (sidebar->shortcuts, location);
|
||||
g_list_store_append (sidebar->shortcuts, location);
|
||||
|
||||
update_places (sidebar);
|
||||
}
|
||||
@@ -4842,43 +4830,46 @@ void
|
||||
gtk_places_sidebar_remove_shortcut (GtkPlacesSidebar *sidebar,
|
||||
GFile *location)
|
||||
{
|
||||
GSList *link;
|
||||
GFile *shortcut;
|
||||
guint i, n;
|
||||
|
||||
g_return_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar));
|
||||
g_return_if_fail (G_IS_FILE (location));
|
||||
|
||||
link = find_shortcut_link (sidebar, location);
|
||||
if (!link)
|
||||
return;
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (sidebar->shortcuts));
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GFile *shortcut = g_list_model_get_item (G_LIST_MODEL (sidebar->shortcuts), i);
|
||||
|
||||
shortcut = G_FILE (link->data);
|
||||
g_object_unref (shortcut);
|
||||
if (shortcut == location)
|
||||
{
|
||||
g_list_store_remove (sidebar->shortcuts, i);
|
||||
g_object_unref (shortcut);
|
||||
update_places (sidebar);
|
||||
return;
|
||||
}
|
||||
|
||||
sidebar->shortcuts = g_slist_delete_link (sidebar->shortcuts, link);
|
||||
update_places (sidebar);
|
||||
g_object_unref (shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gtk_places_sidebar_list_shortcuts:
|
||||
* @sidebar: a places sidebar
|
||||
*
|
||||
* Gets the list of shortcuts.
|
||||
* Gets the list of shortcuts, as a list model containing #GFile objects.
|
||||
*
|
||||
* Returns: (element-type GFile) (transfer full):
|
||||
* A #GSList of #GFile of the locations that have been added as
|
||||
* You should not modify the returned list model. Future changes to
|
||||
* @sidebar may or may not affect the returned model.
|
||||
*
|
||||
* Returns: (transfer full): a list model of #GFiles that have been added as
|
||||
* application-specific shortcuts with gtk_places_sidebar_add_shortcut().
|
||||
* To free this list, you can use
|
||||
* |[<!-- language="C" -->
|
||||
* g_slist_free_full (list, (GDestroyNotify) g_object_unref);
|
||||
* ]|
|
||||
*/
|
||||
GSList *
|
||||
gtk_places_sidebar_list_shortcuts (GtkPlacesSidebar *sidebar)
|
||||
GListModel *
|
||||
gtk_places_sidebar_get_shortcuts (GtkPlacesSidebar *sidebar)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_PLACES_SIDEBAR (sidebar), NULL);
|
||||
|
||||
return g_slist_copy_deep (sidebar->shortcuts, (GCopyFunc) g_object_ref, NULL);
|
||||
return G_LIST_MODEL (g_object_ref (sidebar->shortcuts));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -92,7 +92,7 @@ void gtk_places_sidebar_add_shortcut (GtkPlacesSideb
|
||||
GFile *location);
|
||||
void gtk_places_sidebar_remove_shortcut (GtkPlacesSidebar *sidebar,
|
||||
GFile *location);
|
||||
GSList * gtk_places_sidebar_list_shortcuts (GtkPlacesSidebar *sidebar);
|
||||
GListModel * gtk_places_sidebar_get_shortcuts (GtkPlacesSidebar *sidebar);
|
||||
|
||||
GFile * gtk_places_sidebar_get_nth_bookmark (GtkPlacesSidebar *sidebar,
|
||||
gint n);
|
||||
|
||||
@@ -806,7 +806,7 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
|
||||
g_list_store_append (store, dialog->page_setup_list);
|
||||
g_list_store_append (store, dialog->custom_paper_list);
|
||||
g_list_store_append (store, dialog->manage_papers_list);
|
||||
paper_size_list = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PAGE_SETUP, G_LIST_MODEL (store)));
|
||||
paper_size_list = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (store)));
|
||||
gtk_drop_down_set_model (GTK_DROP_DOWN (dialog->paper_size_combo), paper_size_list);
|
||||
g_object_unref (store);
|
||||
g_object_unref (paper_size_list);
|
||||
@@ -1056,7 +1056,7 @@ load_print_backends (GtkPrintUnixDialog *dialog)
|
||||
g_list_store_append (lists, gtk_print_backend_get_printers (backend));
|
||||
}
|
||||
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PRINTER, G_LIST_MODEL (lists)));
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (lists)));
|
||||
|
||||
g_object_unref (lists);
|
||||
|
||||
|
||||
+10
-10
@@ -110,7 +110,7 @@ static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static GType
|
||||
gtk_shortcut_controller_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
return GTK_TYPE_SHORTCUT;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -198,12 +198,6 @@ gtk_shortcut_controller_set_property (GObject *object,
|
||||
case PROP_MODEL:
|
||||
{
|
||||
GListModel *model = g_value_get_object (value);
|
||||
if (model && g_list_model_get_item_type (model) != GTK_TYPE_SHORTCUT)
|
||||
{
|
||||
g_warning ("Setting a model with type '%s' on a shortcut controller that requires 'GtkShortcut'",
|
||||
g_type_name (g_list_model_get_item_type (model)));
|
||||
model = NULL;
|
||||
}
|
||||
if (model == NULL)
|
||||
{
|
||||
self->shortcuts = G_LIST_MODEL (g_list_store_new (GTK_TYPE_SHORTCUT));
|
||||
@@ -309,6 +303,11 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
|
||||
|
||||
index = (self->last_activated + 1 + i) % g_list_model_get_n_items (self->shortcuts);
|
||||
shortcut = g_list_model_get_item (self->shortcuts, index);
|
||||
if (!GTK_IS_SHORTCUT (shortcut))
|
||||
{
|
||||
g_object_unref (shortcut);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (gtk_shortcut_trigger_trigger (gtk_shortcut_get_trigger (shortcut), event, enable_mnemonics))
|
||||
{
|
||||
@@ -484,7 +483,8 @@ gtk_shortcut_controller_set_widget (GtkEventController *controller,
|
||||
for (i = 0, p = g_list_model_get_n_items (G_LIST_MODEL (controller)); i < p; i++)
|
||||
{
|
||||
GtkShortcut *shortcut = g_list_model_get_item (G_LIST_MODEL (controller), i);
|
||||
update_accel (shortcut, widget, TRUE);
|
||||
if (GTK_IS_SHORTCUT (shortcut))
|
||||
update_accel (shortcut, widget, TRUE);
|
||||
g_object_unref (shortcut);
|
||||
}
|
||||
|
||||
@@ -506,7 +506,8 @@ gtk_shortcut_controller_unset_widget (GtkEventController *controller)
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (controller)); i++)
|
||||
{
|
||||
GtkShortcut *shortcut = g_list_model_get_item (G_LIST_MODEL (controller), i);
|
||||
update_accel (shortcut, widget, FALSE);
|
||||
if (GTK_IS_SHORTCUT (shortcut))
|
||||
update_accel (shortcut, widget, FALSE);
|
||||
g_object_unref (shortcut);
|
||||
}
|
||||
#endif
|
||||
@@ -697,7 +698,6 @@ GtkEventController *
|
||||
gtk_shortcut_controller_new_for_model (GListModel *model)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (g_list_model_get_item_type (model) == GTK_TYPE_SHORTCUT, NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SHORTCUT_CONTROLLER,
|
||||
"model", model,
|
||||
|
||||
@@ -49,7 +49,7 @@ gtk_shortcut_manager_create_controllers (GtkWidget *widget)
|
||||
GtkEventController *controller;
|
||||
|
||||
store = g_list_store_new (GTK_TYPE_SHORTCUT_CONTROLLER);
|
||||
model = gtk_flatten_list_model_new (GTK_TYPE_SHORTCUT, G_LIST_MODEL (store));
|
||||
model = gtk_flatten_list_model_new (G_LIST_MODEL (store));
|
||||
g_object_unref (store);
|
||||
g_object_set_data_full (G_OBJECT (widget), "gtk-shortcut-manager-bubble", model, g_object_unref);
|
||||
controller = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (model));
|
||||
@@ -57,7 +57,7 @@ gtk_shortcut_manager_create_controllers (GtkWidget *widget)
|
||||
gtk_widget_add_controller (widget, controller);
|
||||
|
||||
store = g_list_store_new (GTK_TYPE_SHORTCUT_CONTROLLER);
|
||||
model = gtk_flatten_list_model_new (GTK_TYPE_SHORTCUT, G_LIST_MODEL (store));
|
||||
model = gtk_flatten_list_model_new (G_LIST_MODEL (store));
|
||||
g_object_unref (store);
|
||||
g_object_set_data_full (G_OBJECT (widget), "gtk-shortcut-manager-capture", model, g_object_unref);
|
||||
controller = gtk_shortcut_controller_new_for_model (G_LIST_MODEL (model));
|
||||
|
||||
+65
-10
@@ -72,9 +72,7 @@ static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static GType
|
||||
gtk_single_selection_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSingleSelection *self = GTK_SINGLE_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -82,6 +80,9 @@ gtk_single_selection_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSingleSelection *self = GTK_SINGLE_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
@@ -91,6 +92,9 @@ gtk_single_selection_get_item (GListModel *list,
|
||||
{
|
||||
GtkSingleSelection *self = GTK_SINGLE_SELECTION (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
@@ -307,12 +311,7 @@ gtk_single_selection_set_property (GObject *object,
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_single_selection_clear_model (self);
|
||||
self->model = g_value_dup_object (value);
|
||||
g_signal_connect (self->model, "items-changed",
|
||||
G_CALLBACK (gtk_single_selection_items_changed_cb), self);
|
||||
if (self->autoselect)
|
||||
gtk_single_selection_set_selected (self, 0);
|
||||
gtk_single_selection_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
@@ -440,7 +439,7 @@ gtk_single_selection_class_init (GtkSingleSelectionClass *klass)
|
||||
P_("The model"),
|
||||
P_("The model being managed"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
@@ -486,6 +485,62 @@ gtk_single_selection_get_model (GtkSingleSelection *self)
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_single_selection_set_model:
|
||||
* @self: a #GtkSingleSelection
|
||||
* @model: (allow-none): A #GListModel to wrap
|
||||
*
|
||||
* Sets the model that @self should wrap. If @model is %NULL, @self
|
||||
* will be empty.
|
||||
**/
|
||||
void
|
||||
gtk_single_selection_set_model (GtkSingleSelection *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint n_items_before;
|
||||
|
||||
g_return_if_fail (GTK_IS_SINGLE_SELECTION (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
|
||||
n_items_before = self->model ? g_list_model_get_n_items (self->model) : 0;
|
||||
gtk_single_selection_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (self->model, "items-changed",
|
||||
G_CALLBACK (gtk_single_selection_items_changed_cb), self);
|
||||
gtk_single_selection_items_changed_cb (self->model,
|
||||
0,
|
||||
n_items_before,
|
||||
g_list_model_get_n_items (model),
|
||||
self);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->selected != GTK_INVALID_LIST_POSITION)
|
||||
{
|
||||
self->selected = GTK_INVALID_LIST_POSITION;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
}
|
||||
if (self->selected_item)
|
||||
{
|
||||
g_clear_object (&self->selected_item);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
}
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items_before, 0);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_single_selection_get_selected:
|
||||
* @self: a #GtkSingleSelection
|
||||
|
||||
+13
-10
@@ -35,22 +35,25 @@ GtkSingleSelection * gtk_single_selection_new (GListModel
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_single_selection_get_model (GtkSingleSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_single_selection_get_selected (GtkSingleSelection *self);
|
||||
void gtk_single_selection_set_model (GtkSingleSelection *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_single_selection_set_selected (GtkSingleSelection *self,
|
||||
guint position);
|
||||
guint gtk_single_selection_get_selected (GtkSingleSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gpointer gtk_single_selection_get_selected_item (GtkSingleSelection *self);
|
||||
void gtk_single_selection_set_selected (GtkSingleSelection *self,
|
||||
guint position);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_single_selection_get_autoselect (GtkSingleSelection *self);
|
||||
gpointer gtk_single_selection_get_selected_item (GtkSingleSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_single_selection_set_autoselect (GtkSingleSelection *self,
|
||||
gboolean autoselect);
|
||||
gboolean gtk_single_selection_get_autoselect (GtkSingleSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_single_selection_get_can_unselect (GtkSingleSelection *self);
|
||||
void gtk_single_selection_set_autoselect (GtkSingleSelection *self,
|
||||
gboolean autoselect);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_single_selection_set_can_unselect (GtkSingleSelection *self,
|
||||
gboolean can_unselect);
|
||||
gboolean gtk_single_selection_get_can_unselect (GtkSingleSelection *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_single_selection_set_can_unselect (GtkSingleSelection *self,
|
||||
gboolean can_unselect);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+3
-47
@@ -41,7 +41,6 @@
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
PROP_OFFSET,
|
||||
PROP_SIZE,
|
||||
@@ -52,7 +51,6 @@ struct _GtkSliceListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
guint offset;
|
||||
guint size;
|
||||
@@ -70,9 +68,7 @@ static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
static GType
|
||||
gtk_slice_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSliceListModel *self = GTK_SLICE_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -182,10 +178,6 @@ gtk_slice_list_model_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_slice_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -214,10 +206,6 @@ gtk_slice_list_model_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
@@ -265,18 +253,6 @@ gtk_slice_list_model_class_init (GtkSliceListModelClass *class)
|
||||
gobject_class->get_property = gtk_slice_list_model_get_property;
|
||||
gobject_class->dispose = gtk_slice_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:item-type:
|
||||
*
|
||||
* The #GType for elements of this object
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of elements of this object"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSliceListModel:model:
|
||||
*
|
||||
@@ -324,7 +300,7 @@ gtk_slice_list_model_init (GtkSliceListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_new:
|
||||
* @model: (transfer none): The model to use
|
||||
* @model: (transfer none) (allow-none): The model to use
|
||||
* @offset: the offset of the slice
|
||||
* @size: maximum size of the slice
|
||||
*
|
||||
@@ -338,35 +314,15 @@ gtk_slice_list_model_new (GListModel *model,
|
||||
guint offset,
|
||||
guint size)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SLICE_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"offset", offset,
|
||||
"size", size,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_new_for_type:
|
||||
* @item_type: the type of items
|
||||
*
|
||||
* Creates a new empty #GtkSliceListModel for the given @item_type that
|
||||
* can be set up later.
|
||||
*
|
||||
* Returns: a new empty #GtkSliceListModel
|
||||
**/
|
||||
GtkSliceListModel *
|
||||
gtk_slice_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SLICE_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_slice_list_model_set_model:
|
||||
* @self: a #GtkSliceListModel
|
||||
|
||||
@@ -40,8 +40,6 @@ GDK_AVAILABLE_IN_ALL
|
||||
GtkSliceListModel * gtk_slice_list_model_new (GListModel *model,
|
||||
guint offset,
|
||||
guint size);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSliceListModel * gtk_slice_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_slice_list_model_set_model (GtkSliceListModel *self,
|
||||
|
||||
+115
-32
@@ -34,6 +34,11 @@
|
||||
|
||||
#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
|
||||
@@ -54,6 +59,85 @@
|
||||
* 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
|
||||
@@ -61,11 +145,11 @@ gtk_snapshot_dispose (GObject *object)
|
||||
{
|
||||
GtkSnapshot *snapshot = GTK_SNAPSHOT (object);
|
||||
|
||||
if (snapshot->state_stack)
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
gsk_render_node_unref (gtk_snapshot_to_node (snapshot));
|
||||
|
||||
g_assert (snapshot->state_stack == NULL);
|
||||
g_assert (snapshot->nodes == NULL);
|
||||
g_assert (gtk_snapshot_states_is_empty (&snapshot->state_stack));
|
||||
g_assert (gtk_snapshot_nodes_is_empty (&snapshot->nodes));
|
||||
|
||||
G_OBJECT_CLASS (gtk_snapshot_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -112,15 +196,15 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
GskTransform *transform,
|
||||
GtkSnapshotCollectFunc collect_func)
|
||||
{
|
||||
const gsize n_states = snapshot->state_stack->len;
|
||||
const gsize n_states = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
GtkSnapshotState *state;
|
||||
|
||||
g_array_set_size (snapshot->state_stack, n_states + 1);
|
||||
state = &g_array_index (snapshot->state_stack, GtkSnapshotState, n_states);
|
||||
gtk_snapshot_states_set_size (&snapshot->state_stack, n_states + 1);
|
||||
state = gtk_snapshot_states_get (&snapshot->state_stack, n_states);
|
||||
|
||||
state->transform = gsk_transform_ref (transform);
|
||||
state->collect_func = collect_func;
|
||||
state->start_node_index = snapshot->nodes->len;
|
||||
state->start_node_index = gtk_snapshot_nodes_get_size (&snapshot->nodes);
|
||||
state->n_nodes = 0;
|
||||
|
||||
return state;
|
||||
@@ -129,17 +213,21 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_current_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
g_assert (snapshot->state_stack->len > 0);
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 1);
|
||||
g_assert (size > 0);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 1);
|
||||
}
|
||||
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_previous_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
g_assert (snapshot->state_stack->len > 1);
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 2);
|
||||
g_assert (size > 1);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 2);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -162,9 +250,8 @@ gtk_snapshot_new (void)
|
||||
|
||||
snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
|
||||
|
||||
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_states_init (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_init (&snapshot->nodes);
|
||||
|
||||
gtk_snapshot_push_state (snapshot,
|
||||
NULL,
|
||||
@@ -1029,30 +1116,28 @@ gtk_snapshot_pop_one (GtkSnapshot *snapshot)
|
||||
guint state_index;
|
||||
GskRenderNode *node;
|
||||
|
||||
if (snapshot->state_stack->len == 0)
|
||||
if (gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_pop() calls.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = gtk_snapshot_get_current_state (snapshot);
|
||||
state_index = snapshot->state_stack->len - 1;
|
||||
state_index = gtk_snapshot_states_get_size (&snapshot->state_stack) - 1;
|
||||
|
||||
if (state->collect_func)
|
||||
{
|
||||
node = state->collect_func (snapshot,
|
||||
state,
|
||||
(GskRenderNode **) snapshot->nodes->pdata + state->start_node_index,
|
||||
(GskRenderNode **) gtk_snapshot_nodes_index (&snapshot->nodes, state->start_node_index),
|
||||
state->n_nodes);
|
||||
|
||||
/* The collect func may not modify the state stack... */
|
||||
g_assert (state_index == snapshot->state_stack->len - 1);
|
||||
g_assert (state_index == gtk_snapshot_states_get_size (&snapshot->state_stack) - 1);
|
||||
|
||||
/* Remove all the state's nodes from the list of nodes */
|
||||
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);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1063,10 +1148,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 == snapshot->nodes->len);
|
||||
g_assert (previous_state->start_node_index + previous_state->n_nodes == gtk_snapshot_nodes_get_size (&snapshot->nodes));
|
||||
}
|
||||
|
||||
g_array_remove_index (snapshot->state_stack, state_index);
|
||||
gtk_snapshot_states_splice (&snapshot->state_stack, state_index, 1, NULL, 0);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -1081,7 +1166,7 @@ gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
|
||||
|
||||
if (current_state)
|
||||
{
|
||||
g_ptr_array_add (snapshot->nodes, node);
|
||||
gtk_snapshot_nodes_append (&snapshot->nodes, node);
|
||||
current_state->n_nodes ++;
|
||||
}
|
||||
else
|
||||
@@ -1162,16 +1247,14 @@ gtk_snapshot_to_node (GtkSnapshot *snapshot)
|
||||
result = gtk_snapshot_pop_internal (snapshot);
|
||||
|
||||
/* We should have exactly our initial state */
|
||||
if (snapshot->state_stack->len > 0)
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %u states remaining.", snapshot->state_stack->len);
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %zu states remaining.",
|
||||
gtk_snapshot_states_get_size (&snapshot->state_stack));
|
||||
}
|
||||
|
||||
g_array_free (snapshot->state_stack, TRUE);
|
||||
g_ptr_array_free (snapshot->nodes, TRUE);
|
||||
|
||||
snapshot->state_stack = NULL;
|
||||
snapshot->nodes = NULL;
|
||||
gtk_snapshot_states_clear (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_clear (&snapshot->nodes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -24,76 +24,6 @@
|
||||
|
||||
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,
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright © 2018 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 "gtksor2listmodel.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GObject *
|
||||
#define GTK_VECTOR_TYPE_NAME SortArray
|
||||
#define GTK_VECTOR_NAME sort_array
|
||||
#define GTK_VECTOR_FREE_FUNC g_object_unref
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtksor2listmodel
|
||||
* @title: GtkSor2ListModel
|
||||
* @short_description: A list model that sorts its items
|
||||
* @see_also: #GListModel, #GtkSorter
|
||||
*
|
||||
* #GtkSor2ListModel is a list model that takes a list model and
|
||||
* sorts its elements according to a #GtkSorter.
|
||||
*
|
||||
* #GtkSor2ListModel is a generic model and because of that it
|
||||
* cannot take advantage of any external knowledge when sorting.
|
||||
* If you run into performance issues with #GtkSor2ListModel, it
|
||||
* is strongly recommended that you write your own sorting list
|
||||
* model.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODEL,
|
||||
PROP_SORTER,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
struct _GtkSor2ListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *model;
|
||||
GtkSorter *sorter;
|
||||
|
||||
SortArray items; /* empty if known unsorted */
|
||||
};
|
||||
|
||||
struct _GtkSor2ListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_sor2_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_sor2_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSor2ListModel *self = GTK_SOR2_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_sor2_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkSor2ListModel *self = GTK_SOR2_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
if (sort_array_is_empty (&self->items))
|
||||
return g_list_model_get_item (self->model, position);
|
||||
|
||||
if (position >= sort_array_get_size (&self->items))
|
||||
return NULL;
|
||||
|
||||
return g_object_ref (sort_array_get (&self->items, position));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_sor2_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_sor2_list_model_get_n_items;
|
||||
iface->get_item = gtk_sor2_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkSor2ListModel, gtk_sor2_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_sor2_list_model_model_init))
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_clear_items (GtkSor2ListModel *self)
|
||||
{
|
||||
sort_array_clear (&self->items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_create_items (GtkSor2ListModel *self)
|
||||
{
|
||||
guint i, n_items;
|
||||
|
||||
if (self->sorter == NULL ||
|
||||
self->model == NULL ||
|
||||
gtk_sorter_get_order (self->sorter) == GTK_SORTER_ORDER_NONE)
|
||||
return;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
sort_array_reserve (&self->items, n_items);
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
sort_array_append (&self->items, g_list_model_get_item (self->model, i));
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sort_func (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer data)
|
||||
{
|
||||
return gtk_sorter_compare (data, *(GObject **) a, *(GObject **) b);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_resort (GtkSor2ListModel *self)
|
||||
{
|
||||
g_qsort_with_data (sort_array_get_data (&self->items),
|
||||
sort_array_get_size (&self->items),
|
||||
sizeof (GObject *),
|
||||
sort_func,
|
||||
self->sorter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkSor2ListModel *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
/* doesn't free() the array */
|
||||
sort_array_set_size (&self->items, 0);
|
||||
gtk_sor2_list_model_create_items (self);
|
||||
gtk_sor2_list_model_resort (self);
|
||||
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items - added + removed, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSor2ListModel *self = GTK_SOR2_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
gtk_sor2_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
gtk_sor2_list_model_set_sorter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSor2ListModel *self = GTK_SOR2_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
g_value_set_object (value, self->sorter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_sorter_changed_cb (GtkSorter *sorter,
|
||||
int change,
|
||||
GtkSor2ListModel *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
if (gtk_sorter_get_order (sorter) == GTK_SORTER_ORDER_NONE)
|
||||
gtk_sor2_list_model_clear_items (self);
|
||||
else if (sort_array_is_empty (&self->items))
|
||||
gtk_sor2_list_model_create_items (self);
|
||||
|
||||
gtk_sor2_list_model_resort (self);
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
if (n_items > 1)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_clear_model (GtkSor2ListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_sor2_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
gtk_sor2_list_model_clear_items (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_clear_sorter (GtkSor2ListModel *self)
|
||||
{
|
||||
if (self->sorter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->sorter, gtk_sor2_list_model_sorter_changed_cb, self);
|
||||
g_clear_object (&self->sorter);
|
||||
gtk_sor2_list_model_clear_items (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkSor2ListModel *self = GTK_SOR2_LIST_MODEL (object);
|
||||
|
||||
gtk_sor2_list_model_clear_model (self);
|
||||
gtk_sor2_list_model_clear_sorter (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_sor2_list_model_parent_class)->dispose (object);
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_class_init (GtkSor2ListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_sor2_list_model_set_property;
|
||||
gobject_class->get_property = gtk_sor2_list_model_get_property;
|
||||
gobject_class->dispose = gtk_sor2_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSor2ListModel:sorter:
|
||||
*
|
||||
* The sorter for this model
|
||||
*/
|
||||
properties[PROP_SORTER] =
|
||||
g_param_spec_object ("sorter",
|
||||
P_("Sorter"),
|
||||
P_("The sorter for this model"),
|
||||
GTK_TYPE_SORTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSor2ListModel:model:
|
||||
*
|
||||
* The model being sorted
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("The model being sorted"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor2_list_model_init (GtkSor2ListModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor2_list_model_new:
|
||||
* @model: (allow-none): the model to sort
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Creates a new sort list model that uses the @sorter to sort @model.
|
||||
*
|
||||
* Returns: a new #GtkSor2ListModel
|
||||
**/
|
||||
GtkSor2ListModel *
|
||||
gtk_sor2_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
GtkSor2ListModel *result;
|
||||
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (sorter == NULL || GTK_IS_SORTER (sorter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_SOR2_LIST_MODEL,
|
||||
"model", model,
|
||||
"sorter", sorter,
|
||||
NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor2_list_model_set_model:
|
||||
* @self: a #GtkSor2ListModel
|
||||
* @model: (allow-none): The model to be sorted
|
||||
*
|
||||
* Sets the model to be sorted. The @model's item type must conform to
|
||||
* the item type of @self.
|
||||
**/
|
||||
void
|
||||
gtk_sor2_list_model_set_model (GtkSor2ListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added;
|
||||
|
||||
g_return_if_fail (GTK_IS_SOR2_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_sor2_list_model_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_sor2_list_model_items_changed_cb), self);
|
||||
added = g_list_model_get_n_items (model);
|
||||
|
||||
gtk_sor2_list_model_create_items (self);
|
||||
gtk_sor2_list_model_resort (self);
|
||||
}
|
||||
else
|
||||
added = 0;
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor2_list_model_get_model:
|
||||
* @self: a #GtkSor2ListModel
|
||||
*
|
||||
* Gets the model currently sorted or %NULL if none.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model that gets sorted
|
||||
**/
|
||||
GListModel *
|
||||
gtk_sor2_list_model_get_model (GtkSor2ListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SOR2_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor2_list_model_set_sorter:
|
||||
* @self: a #GtkSor2ListModel
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Sets a new sorter on @self.
|
||||
*/
|
||||
void
|
||||
gtk_sor2_list_model_set_sorter (GtkSor2ListModel *self,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_SOR2_LIST_MODEL (self));
|
||||
g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
|
||||
|
||||
gtk_sor2_list_model_clear_sorter (self);
|
||||
|
||||
if (sorter)
|
||||
{
|
||||
self->sorter = g_object_ref (sorter);
|
||||
g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sor2_list_model_sorter_changed_cb), self);
|
||||
gtk_sor2_list_model_sorter_changed_cb (sorter, GTK_SORTER_CHANGE_DIFFERENT, self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor2_list_model_get_sorter:
|
||||
* @self: a #GtkSor2LisTModel
|
||||
*
|
||||
* Gets the sorter that is used to sort @self.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the sorter of #self
|
||||
*/
|
||||
GtkSorter *
|
||||
gtk_sor2_list_model_get_sorter (GtkSor2ListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SOR2_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->sorter;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright © 2018 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_SOR2_LIST_MODEL_H__
|
||||
#define __GTK_SOR2_LIST_MODEL_H__
|
||||
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SOR2_LIST_MODEL (gtk_sor2_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkSor2ListModel, gtk_sor2_list_model, GTK, SOR2_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSor2ListModel * gtk_sor2_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sor2_list_model_set_sorter (GtkSor2ListModel *self,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_sor2_list_model_get_sorter (GtkSor2ListModel *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sor2_list_model_set_model (GtkSor2ListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_sor2_list_model_get_model (GtkSor2ListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SOR2_LIST_MODEL_H__ */
|
||||
@@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Copyright © 2018 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 "gtksor3listmodel.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GObject *
|
||||
#define GTK_VECTOR_TYPE_NAME SortArray
|
||||
#define GTK_VECTOR_NAME sort_array
|
||||
#define GTK_VECTOR_FREE_FUNC g_object_unref
|
||||
#define GTK_VECTOR_PREALLOC 16
|
||||
#include "gtkvectorimpl.c"
|
||||
#undef GTK_VECTOR_ELEMENT_TYPE
|
||||
#undef GTK_VECTOR_TYPE_NAME
|
||||
#undef GTK_VECTOR_NAME
|
||||
#undef GTK_VECTOR_FREE_FUNC
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE guint
|
||||
#define GTK_VECTOR_TYPE_NAME PivotStack
|
||||
#define GTK_VECTOR_NAME pivot_stack
|
||||
#define GTK_VECTOR_BY_VALUE
|
||||
#define GTK_VECTOR_PREALLOC 16
|
||||
#include "gtkvectorimpl.c"
|
||||
#undef GTK_VECTOR_ELEMENT_TYPE
|
||||
#undef GTK_VECTOR_TYPE_NAME
|
||||
#undef GTK_VECTOR_NAME
|
||||
#undef GTK_VECTOR_BY_VALUE
|
||||
#undef GTK_VECTOR_FREE_FUNC
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
|
||||
static inline void
|
||||
pivot_stack_push (PivotStack *stack,
|
||||
guint pos)
|
||||
{
|
||||
gsize size = pivot_stack_get_size (stack);
|
||||
pivot_stack_set_size (stack, size + 1);
|
||||
*pivot_stack_get (stack, size) = pos;
|
||||
}
|
||||
|
||||
static inline guint
|
||||
pivot_stack_top (PivotStack *stack)
|
||||
{
|
||||
return *pivot_stack_get (stack, pivot_stack_get_size (stack) - 1);
|
||||
}
|
||||
|
||||
static inline guint
|
||||
pivot_stack_pop (PivotStack *stack)
|
||||
{
|
||||
gsize size = pivot_stack_get_size (stack);
|
||||
guint top = *pivot_stack_get (stack, size - 1);
|
||||
pivot_stack_set_size (stack, size - 1);
|
||||
return top;
|
||||
}
|
||||
|
||||
/**
|
||||
* SECTION:gtksor3listmodel
|
||||
* @title: GtkSor3ListModel
|
||||
* @short_description: A list model that sorts its items
|
||||
* @see_also: #GListModel, #GtkSorter
|
||||
*
|
||||
* #GtkSor3ListModel is a list model that takes a list model and
|
||||
* sorts its elements according to a #GtkSorter.
|
||||
*
|
||||
* #GtkSor3ListModel is a generic model and because of that it
|
||||
* cannot take advantage of any external knowledge when sorting.
|
||||
* If you run into performance issues with #GtkSor3ListModel, it
|
||||
* is strongly recommended that you write your own sorting list
|
||||
* model.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODEL,
|
||||
PROP_SORTER,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
struct _GtkSor3ListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *model;
|
||||
GtkSorter *sorter;
|
||||
|
||||
SortArray items; /* empty if known unsorted */
|
||||
|
||||
guint sorting_cb;
|
||||
guint sorted_to;
|
||||
PivotStack stack;
|
||||
};
|
||||
|
||||
struct _GtkSor3ListModelClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_sor3_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_sor3_list_model_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return 0;
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_sor3_list_model_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (list);
|
||||
|
||||
if (self->model == NULL)
|
||||
return NULL;
|
||||
|
||||
if (sort_array_is_empty (&self->items))
|
||||
return g_list_model_get_item (self->model, position);
|
||||
|
||||
if (position >= sort_array_get_size (&self->items))
|
||||
return NULL;
|
||||
|
||||
return g_object_ref (sort_array_get (&self->items, position));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_sor3_list_model_get_item_type;
|
||||
iface->get_n_items = gtk_sor3_list_model_get_n_items;
|
||||
iface->get_item = gtk_sor3_list_model_get_item;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkSor3ListModel, gtk_sor3_list_model, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_sor3_list_model_model_init))
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_clear_items (GtkSor3ListModel *self)
|
||||
{
|
||||
sort_array_clear (&self->items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_create_items (GtkSor3ListModel *self)
|
||||
{
|
||||
guint i, n_items;
|
||||
|
||||
if (self->sorter == NULL ||
|
||||
self->model == NULL ||
|
||||
gtk_sorter_get_order (self->sorter) == GTK_SORTER_ORDER_NONE)
|
||||
return;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
sort_array_reserve (&self->items, n_items);
|
||||
for (i = 0; i < n_items; i++)
|
||||
sort_array_append (&self->items, g_list_model_get_item (self->model, i));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_stop_sorting (GtkSor3ListModel *self)
|
||||
{
|
||||
g_clear_handle_id (&self->sorting_cb, g_source_remove);
|
||||
pivot_stack_set_size (&self->stack, 0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
compare (GtkSorter *sorter, GObject *a, GObject *b)
|
||||
{
|
||||
return gtk_sorter_compare (sorter, a, b);
|
||||
}
|
||||
|
||||
static inline void
|
||||
swap (SortArray *items, guint i, guint j)
|
||||
{
|
||||
GObject *tmp = sort_array_get (items, i);
|
||||
*sort_array_index (items, i) = sort_array_get (items, j);
|
||||
*sort_array_index (items, j) = tmp;
|
||||
}
|
||||
|
||||
/* This is pretty much the incremental quicksort that is described
|
||||
* in the wikipedia article about it. Calling iqs repeatedly for
|
||||
* each position from 0..k gives you that k smallest elements, in
|
||||
* order. Which is what we do. As a side-effect, the array ends up
|
||||
* getting sorted. The nice thing is that we simply remember how
|
||||
* far we've enumerated (in sorted_to), and interrupt the sorting,
|
||||
* which is the incremental part.
|
||||
*/
|
||||
static guint
|
||||
partition (SortArray *items, guint first, guint end, GtkSorter *sorter)
|
||||
{
|
||||
guint mid;
|
||||
guint i, j;
|
||||
GObject *pivot;
|
||||
|
||||
mid = first + (end - first) / 2;
|
||||
if (compare (sorter, sort_array_get (items, mid),
|
||||
sort_array_get (items, first)) < 0)
|
||||
swap (items, mid, first);
|
||||
if (compare (sorter, sort_array_get (items, end),
|
||||
sort_array_get (items, first)) < 0)
|
||||
swap (items, end, first);
|
||||
if (compare (sorter, sort_array_get (items, mid),
|
||||
sort_array_get (items, end)) < 0)
|
||||
swap (items, mid, end);
|
||||
|
||||
pivot = sort_array_get (items, end);
|
||||
|
||||
i = first;
|
||||
j = end;
|
||||
while (1)
|
||||
{
|
||||
while (compare (sorter, sort_array_get (items, i), pivot) < 0) i++;
|
||||
while (j > i && compare (sorter, sort_array_get (items, j), pivot) >= 0) j--;
|
||||
if (i >= j) return j;
|
||||
swap (items, i, j);
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
iqs (SortArray *items, guint pos, PivotStack *stack, GtkSorter *sorter)
|
||||
{
|
||||
guint top;
|
||||
guint pivot;
|
||||
|
||||
top = pivot_stack_top (stack);
|
||||
if (top == pos)
|
||||
{
|
||||
pivot_stack_pop (stack);
|
||||
return sort_array_get (items, pos);
|
||||
}
|
||||
|
||||
pivot = partition (items, pos, top, sorter);
|
||||
pivot_stack_push (stack, pivot);
|
||||
|
||||
return iqs (items, pos, stack, sorter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_sor3_list_model_sort_cb (gpointer data)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (data);
|
||||
guint start;
|
||||
guint end;
|
||||
guint n_items;
|
||||
guint i;
|
||||
|
||||
start = self->sorted_to;
|
||||
n_items = sort_array_get_size (&self->items);
|
||||
end = MIN (512, n_items - start);
|
||||
|
||||
for (i = 0; i < end; i++)
|
||||
{
|
||||
iqs (&self->items, self->sorted_to, &self->stack, self->sorter);
|
||||
self->sorted_to++;
|
||||
}
|
||||
|
||||
if (self->sorted_to >= n_items)
|
||||
gtk_sor3_list_model_stop_sorting (self);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), start, n_items - start, n_items - start);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_start_sorting (GtkSor3ListModel *self)
|
||||
{
|
||||
if (sort_array_get_size (&self->items) == 0)
|
||||
return;
|
||||
|
||||
g_assert (pivot_stack_get_size (&self->stack) == 0);
|
||||
g_assert (self->sorting_cb == 0);
|
||||
|
||||
pivot_stack_push (&self->stack, (guint)sort_array_get_size (&self->items) - 1);
|
||||
self->sorted_to = 0;
|
||||
|
||||
self->sorting_cb = g_idle_add (gtk_sor3_list_model_sort_cb, self);
|
||||
g_source_set_name_by_id (self->sorting_cb, "[gtk] gtk_sor3_list_model_sort_cb");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_resort (GtkSor3ListModel *self)
|
||||
{
|
||||
gtk_sor3_list_model_stop_sorting (self);
|
||||
gtk_sor3_list_model_start_sorting (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkSor3ListModel *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
/* doesn't free() the array */
|
||||
sort_array_set_size (&self->items, 0);
|
||||
gtk_sor3_list_model_create_items (self);
|
||||
gtk_sor3_list_model_resort (self);
|
||||
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items - added + removed, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
gtk_sor3_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
gtk_sor3_list_model_set_sorter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_SORTER:
|
||||
g_value_set_object (value, self->sorter);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_sorter_changed_cb (GtkSorter *sorter,
|
||||
int change,
|
||||
GtkSor3ListModel *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
if (gtk_sorter_get_order (sorter) == GTK_SORTER_ORDER_NONE)
|
||||
gtk_sor3_list_model_clear_items (self);
|
||||
else if (sort_array_is_empty (&self->items))
|
||||
gtk_sor3_list_model_create_items (self);
|
||||
|
||||
gtk_sor3_list_model_resort (self);
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
if (n_items > 1)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_clear_model (GtkSor3ListModel *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model, gtk_sor3_list_model_items_changed_cb, self);
|
||||
g_clear_object (&self->model);
|
||||
gtk_sor3_list_model_stop_sorting (self);
|
||||
gtk_sor3_list_model_clear_items (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_clear_sorter (GtkSor3ListModel *self)
|
||||
{
|
||||
if (self->sorter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->sorter, gtk_sor3_list_model_sorter_changed_cb, self);
|
||||
g_clear_object (&self->sorter);
|
||||
gtk_sor3_list_model_stop_sorting (self);
|
||||
gtk_sor3_list_model_clear_items (self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_dispose (GObject *object)
|
||||
{
|
||||
GtkSor3ListModel *self = GTK_SOR3_LIST_MODEL (object);
|
||||
|
||||
gtk_sor3_list_model_stop_sorting (self);
|
||||
gtk_sor3_list_model_clear_model (self);
|
||||
gtk_sor3_list_model_clear_sorter (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_sor3_list_model_parent_class)->dispose (object);
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_class_init (GtkSor3ListModelClass *class)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->set_property = gtk_sor3_list_model_set_property;
|
||||
gobject_class->get_property = gtk_sor3_list_model_get_property;
|
||||
gobject_class->dispose = gtk_sor3_list_model_dispose;
|
||||
|
||||
/**
|
||||
* GtkSor3ListModel:sorter:
|
||||
*
|
||||
* The sorter for this model
|
||||
*/
|
||||
properties[PROP_SORTER] =
|
||||
g_param_spec_object ("sorter",
|
||||
P_("Sorter"),
|
||||
P_("The sorter for this model"),
|
||||
GTK_TYPE_SORTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSor3ListModel:model:
|
||||
*
|
||||
* The model being sorted
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("The model being sorted"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_sor3_list_model_init (GtkSor3ListModel *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor3_list_model_new:
|
||||
* @model: (allow-none): the model to sort
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Creates a new sort list model that uses the @sorter to sort @model.
|
||||
*
|
||||
* Returns: a new #GtkSor3ListModel
|
||||
**/
|
||||
GtkSor3ListModel *
|
||||
gtk_sor3_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
GtkSor3ListModel *result;
|
||||
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (sorter == NULL || GTK_IS_SORTER (sorter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_SOR3_LIST_MODEL,
|
||||
"model", model,
|
||||
"sorter", sorter,
|
||||
NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor3_list_model_set_model:
|
||||
* @self: a #GtkSor3ListModel
|
||||
* @model: (allow-none): The model to be sorted
|
||||
*
|
||||
* Sets the model to be sorted. The @model's item type must conform to
|
||||
* the item type of @self.
|
||||
**/
|
||||
void
|
||||
gtk_sor3_list_model_set_model (GtkSor3ListModel *self,
|
||||
GListModel *model)
|
||||
{
|
||||
guint removed, added;
|
||||
|
||||
g_return_if_fail (GTK_IS_SOR3_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
gtk_sor3_list_model_clear_model (self);
|
||||
|
||||
if (model)
|
||||
{
|
||||
self->model = g_object_ref (model);
|
||||
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_sor3_list_model_items_changed_cb), self);
|
||||
added = g_list_model_get_n_items (model);
|
||||
|
||||
gtk_sor3_list_model_create_items (self);
|
||||
gtk_sor3_list_model_resort (self);
|
||||
}
|
||||
else
|
||||
added = 0;
|
||||
|
||||
if (removed > 0 || added > 0)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor3_list_model_get_model:
|
||||
* @self: a #GtkSor3ListModel
|
||||
*
|
||||
* Gets the model currently sorted or %NULL if none.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model that gets sorted
|
||||
**/
|
||||
GListModel *
|
||||
gtk_sor3_list_model_get_model (GtkSor3ListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SOR3_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor3_list_model_set_sorter:
|
||||
* @self: a #GtkSor3ListModel
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Sets a new sorter on @self.
|
||||
*/
|
||||
void
|
||||
gtk_sor3_list_model_set_sorter (GtkSor3ListModel *self,
|
||||
GtkSorter *sorter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_SOR3_LIST_MODEL (self));
|
||||
g_return_if_fail (sorter == NULL || GTK_IS_SORTER (sorter));
|
||||
|
||||
gtk_sor3_list_model_clear_sorter (self);
|
||||
|
||||
if (sorter)
|
||||
{
|
||||
self->sorter = g_object_ref (sorter);
|
||||
g_signal_connect (sorter, "changed", G_CALLBACK (gtk_sor3_list_model_sorter_changed_cb), self);
|
||||
gtk_sor3_list_model_sorter_changed_cb (sorter, GTK_SORTER_CHANGE_DIFFERENT, self);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SORTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sor3_list_model_get_sorter:
|
||||
* @self: a #GtkSor3LisTModel
|
||||
*
|
||||
* Gets the sorter that is used to sort @self.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): the sorter of #self
|
||||
*/
|
||||
GtkSorter *
|
||||
gtk_sor3_list_model_get_sorter (GtkSor3ListModel *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SOR3_LIST_MODEL (self), NULL);
|
||||
|
||||
return self->sorter;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright © 2018 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_SOR3_LIST_MODEL_H__
|
||||
#define __GTK_SOR3_LIST_MODEL_H__
|
||||
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_SOR3_LIST_MODEL (gtk_sor3_list_model_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkSor3ListModel, gtk_sor3_list_model, GTK, SOR3_LIST_MODEL, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSor3ListModel * gtk_sor3_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sor3_list_model_set_sorter (GtkSor3ListModel *self,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_sor3_list_model_get_sorter (GtkSor3ListModel *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sor3_list_model_set_model (GtkSor3ListModel *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_sor3_list_model_get_model (GtkSor3ListModel *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_SOR3_LIST_MODEL_H__ */
|
||||
+2
-1
@@ -142,7 +142,8 @@ gtk_sorter_compare (GtkSorter *self,
|
||||
{
|
||||
GtkOrdering result;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SORTER (self), GTK_ORDERING_EQUAL);
|
||||
/* We turn this off because gtk_sorter_compare() is called so much that it's too expensive */
|
||||
/* g_return_val_if_fail (GTK_IS_SORTER (self), GTK_ORDERING_EQUAL); */
|
||||
g_return_val_if_fail (item1 && item2, GTK_ORDERING_EQUAL);
|
||||
|
||||
if (item1 == item2)
|
||||
|
||||
+3
-52
@@ -42,7 +42,6 @@
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
PROP_MODEL,
|
||||
PROP_SORTER,
|
||||
NUM_PROPERTIES
|
||||
@@ -54,7 +53,6 @@ struct _GtkSortListModel
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GListModel *model;
|
||||
GtkSorter *sorter;
|
||||
|
||||
@@ -89,9 +87,7 @@ gtk_sort_list_entry_free (gpointer data)
|
||||
static GType
|
||||
gtk_sort_list_model_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkSortListModel *self = GTK_SORT_LIST_MODEL (list);
|
||||
|
||||
return self->item_type;
|
||||
return G_TYPE_OBJECT;
|
||||
}
|
||||
|
||||
static guint
|
||||
@@ -262,10 +258,6 @@ gtk_sort_list_model_set_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_sort_list_model_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
@@ -290,10 +282,6 @@ gtk_sort_list_model_get_property (GObject *object,
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
@@ -405,18 +393,6 @@ gtk_sort_list_model_class_init (GtkSortListModelClass *class)
|
||||
GTK_TYPE_SORTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSortListModel:item-type:
|
||||
*
|
||||
* The #GType for items of this model
|
||||
*/
|
||||
properties[PROP_ITEM_TYPE] =
|
||||
g_param_spec_gtype ("item-type",
|
||||
P_("Item type"),
|
||||
P_("The type of items of this list"),
|
||||
G_TYPE_OBJECT,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkSortListModel:model:
|
||||
*
|
||||
@@ -439,7 +415,7 @@ gtk_sort_list_model_init (GtkSortListModel *self)
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_new:
|
||||
* @model: the model to sort
|
||||
* @model: (allow-none): the model to sort
|
||||
* @sorter: (allow-none): the #GtkSorter to sort @model with
|
||||
*
|
||||
* Creates a new sort list model that uses the @sorter to sort @model.
|
||||
@@ -452,11 +428,10 @@ gtk_sort_list_model_new (GListModel *model,
|
||||
{
|
||||
GtkSortListModel *result;
|
||||
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (model == NULL || G_IS_LIST_MODEL (model), NULL);
|
||||
g_return_val_if_fail (sorter == NULL || GTK_IS_SORTER (sorter), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_SORT_LIST_MODEL,
|
||||
"item-type", g_list_model_get_item_type (model),
|
||||
"model", model,
|
||||
"sorter", sorter,
|
||||
NULL);
|
||||
@@ -464,26 +439,6 @@ gtk_sort_list_model_new (GListModel *model,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_new_for_type:
|
||||
* @item_type: the type of the items that will be returned
|
||||
*
|
||||
* Creates a new empty sort list model set up to return items of type @item_type.
|
||||
* It is up to the application to set a proper sort function and model to ensure
|
||||
* the item type is matched.
|
||||
*
|
||||
* Returns: a new #GtkSortListModel
|
||||
**/
|
||||
GtkSortListModel *
|
||||
gtk_sort_list_model_new_for_type (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_SORT_LIST_MODEL,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_sort_list_model_set_model:
|
||||
* @self: a #GtkSortListModel
|
||||
@@ -500,10 +455,6 @@ gtk_sort_list_model_set_model (GtkSortListModel *self,
|
||||
|
||||
g_return_if_fail (GTK_IS_SORT_LIST_MODEL (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
if (model)
|
||||
{
|
||||
g_return_if_fail (g_type_is_a (g_list_model_get_item_type (model), self->item_type));
|
||||
}
|
||||
|
||||
if (self->model == model)
|
||||
return;
|
||||
|
||||
@@ -40,9 +40,6 @@ G_DECLARE_FINAL_TYPE (GtkSortListModel, gtk_sort_list_model, GTK, SORT_LIST_MODE
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSortListModel * gtk_sort_list_model_new (GListModel *model,
|
||||
GtkSorter *sorter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSortListModel * gtk_sort_list_model_new_for_type (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_sort_list_model_set_sorter (GtkSortListModel *self,
|
||||
GtkSorter *sorter);
|
||||
|
||||
@@ -110,9 +110,9 @@ gtk_string_filter_match (GtkFilter *filter,
|
||||
!gtk_expression_evaluate (self->expression, item, &value))
|
||||
return FALSE;
|
||||
s = g_value_get_string (&value);
|
||||
if (s == NULL)
|
||||
return FALSE;
|
||||
prepared = gtk_string_filter_prepare (self, s);
|
||||
if (prepared == NULL)
|
||||
return FALSE;
|
||||
|
||||
switch (self->match_mode)
|
||||
{
|
||||
|
||||
+34
-30
@@ -138,20 +138,13 @@ gtk_string_object_class_init (GtkStringObjectClass *class)
|
||||
|
||||
pspec = g_param_spec_string ("string", "String", "String",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_STRING, pspec);
|
||||
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
gtk_string_object_new (const char *string)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_STRING_OBJECT, "string", string, NULL);
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
gtk_string_object_new_take (char *string)
|
||||
{
|
||||
@@ -163,6 +156,20 @@ gtk_string_object_new_take (char *string)
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_object_new:
|
||||
* @string: (non-nullable): The string to wrap
|
||||
*
|
||||
* Wraps a string in an object for use with #GListModel
|
||||
*
|
||||
* Returns: a new #GtkStringObject
|
||||
**/
|
||||
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
|
||||
@@ -432,15 +439,13 @@ gtk_string_list_init (GtkStringList *self)
|
||||
* Returns: a new #GtkStringList
|
||||
*/
|
||||
GtkStringList *
|
||||
gtk_string_list_new (const char **strings)
|
||||
gtk_string_list_new (const char * const *strings)
|
||||
{
|
||||
GtkStringList *self;
|
||||
guint i;
|
||||
|
||||
self = g_object_new (GTK_TYPE_STRING_LIST, NULL);
|
||||
|
||||
for (i = 0; strings[i]; i++)
|
||||
g_sequence_append (self->items, gtk_string_object_new (strings[i]));
|
||||
gtk_string_list_splice (self, 0, 0, strings);
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -450,11 +455,10 @@ gtk_string_list_new (const char **strings)
|
||||
* @self: a #GtkStringList
|
||||
* @position: the position at which to make the change
|
||||
* @n_removals: the number of strings to remove
|
||||
* @additions: (array length=n_additions): the strings to add
|
||||
* @n_additions: the number of items to add
|
||||
* @additions: (array zero-terminated=1) (nullable): The strings to add
|
||||
*
|
||||
* Changes @self by removing @n_removals strings and adding @n_additions
|
||||
* strings to it.
|
||||
* Changes @self by removing @n_removals strings and adding @additions
|
||||
* to it.
|
||||
*
|
||||
* This function is more efficient than gtk_string_list_insert() and
|
||||
* gtk_string_list_remove(), because it only emits
|
||||
@@ -467,14 +471,13 @@ gtk_string_list_new (const char **strings)
|
||||
* of the list at the time this function is called).
|
||||
*/
|
||||
void
|
||||
gtk_string_list_splice (GtkStringList *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char **additions,
|
||||
guint n_additions)
|
||||
gtk_string_list_splice (GtkStringList *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char * const *additions)
|
||||
{
|
||||
GSequenceIter *it;
|
||||
guint n_items;
|
||||
guint add, n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_STRING_LIST (self));
|
||||
g_return_if_fail (position + n_removals >= position); /* overflow */
|
||||
@@ -494,17 +497,18 @@ gtk_string_list_splice (GtkStringList *self,
|
||||
it = end;
|
||||
}
|
||||
|
||||
if (n_additions)
|
||||
if (additions)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_additions; i++)
|
||||
for (add = 0; additions[add]; add++)
|
||||
{
|
||||
g_sequence_insert_before (it, gtk_string_object_new (additions[i]));
|
||||
g_sequence_insert_before (it, gtk_string_object_new (additions[add]));
|
||||
}
|
||||
}
|
||||
else
|
||||
add = 0;
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
|
||||
if (n_removals || add)
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, add);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -589,8 +593,8 @@ gtk_string_list_remove (GtkStringList *self,
|
||||
* @self: a #GtkStringList
|
||||
* @position: the position to get the string for
|
||||
*
|
||||
* Gets the string that is at @position in @self. @position
|
||||
* must be smaller than the current length of the list.
|
||||
* Gets the string that is at @position in @self. If @self
|
||||
* does not contain @position items, %NULL is returned.
|
||||
*
|
||||
* This function returns the const char *. To get the
|
||||
* object wrapping it, use g_list_model_get_item().
|
||||
|
||||
+16
-15
@@ -37,7 +37,9 @@ GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkStringObject, gtk_string_object, GTK, STRING_OBJECT, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_string_object_get_string (GtkStringObject *self);
|
||||
GtkStringObject * gtk_string_object_new (const char *string);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_string_object_get_string (GtkStringObject *self);
|
||||
|
||||
#define GTK_TYPE_STRING_LIST (gtk_string_list_get_type ())
|
||||
|
||||
@@ -45,30 +47,29 @@ GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkStringList, gtk_string_list, GTK, STRING_LIST, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkStringList * gtk_string_list_new (const char **strings);
|
||||
GtkStringList * gtk_string_list_new (const char * const *strings);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list_append (GtkStringList *self,
|
||||
const char *string);
|
||||
void gtk_string_list_append (GtkStringList *self,
|
||||
const char *string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list_take (GtkStringList *self,
|
||||
char *string);
|
||||
void gtk_string_list_take (GtkStringList *self,
|
||||
char *string);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list_remove (GtkStringList *self,
|
||||
guint position);
|
||||
void gtk_string_list_remove (GtkStringList *self,
|
||||
guint position);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_string_list_splice (GtkStringList *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char **additions,
|
||||
guint n_additions);
|
||||
void gtk_string_list_splice (GtkStringList *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
const char * const *additions);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_string_list_get_string (GtkStringList *self,
|
||||
guint position);
|
||||
const char * gtk_string_list_get_string (GtkStringList *self,
|
||||
guint position);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+1
-11
@@ -533,16 +533,6 @@ gtk_tree_list_model_expand_node (GtkTreeListModel *self,
|
||||
if (model == NULL)
|
||||
return 0;
|
||||
|
||||
if (!g_type_is_a (g_list_model_get_item_type (model), g_list_model_get_item_type (self->root_node.model)))
|
||||
{
|
||||
g_critical ("The GtkTreeListModelCreateModelFunc for %p returned a model with item type \"%s\" "
|
||||
"but \"%s\" is required.",
|
||||
self,
|
||||
g_type_name (g_list_model_get_item_type (model)),
|
||||
g_type_name (g_list_model_get_item_type (self->root_node.model)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
gtk_tree_list_model_init_node (self, node, model);
|
||||
|
||||
tree_node_mark_dirty (node);
|
||||
@@ -576,7 +566,7 @@ gtk_tree_list_model_get_item_type (GListModel *list)
|
||||
GtkTreeListModel *self = GTK_TREE_LIST_MODEL (list);
|
||||
|
||||
if (self->passthrough)
|
||||
return g_list_model_get_item_type (self->root_node.model);
|
||||
return G_TYPE_OBJECT;
|
||||
else
|
||||
return GTK_TYPE_TREE_LIST_ROW;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* 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 (GTK_VECTOR_REAL_SIZE (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;
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
self->end_allocation--;
|
||||
#endif
|
||||
}
|
||||
|
||||
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, new_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
|
||||
@@ -245,10 +245,10 @@ gtk_inspector_controllers_set_object (GtkInspectorControllers *self,
|
||||
self->model = gtk_property_lookup_list_model_new (GTK_TYPE_WIDGET, "parent");
|
||||
gtk_property_lookup_list_model_set_object (self->model, object);
|
||||
|
||||
map_model = gtk_map_list_model_new (G_TYPE_LIST_MODEL, G_LIST_MODEL (self->model), map_to_controllers, NULL, NULL);
|
||||
map_model = gtk_map_list_model_new (G_LIST_MODEL (self->model), map_to_controllers, NULL, NULL);
|
||||
g_object_unref (self->model);
|
||||
|
||||
flatten_model = gtk_flatten_list_model_new (GTK_TYPE_EVENT_CONTROLLER, G_LIST_MODEL (map_model));
|
||||
flatten_model = gtk_flatten_list_model_new (G_LIST_MODEL (map_model));
|
||||
|
||||
sorter = gtk_custom_sorter_new (compare_controllers, NULL, NULL);
|
||||
sort_model = gtk_sort_list_model_new (G_LIST_MODEL (flatten_model), sorter);
|
||||
|
||||
@@ -130,7 +130,7 @@ object_tree_widget_get_children (GObject *object)
|
||||
g_list_store_append (list, sublist);
|
||||
g_object_unref (sublist);
|
||||
|
||||
flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
|
||||
flatten = gtk_flatten_list_model_new (G_LIST_MODEL (list));
|
||||
g_object_unref (list);
|
||||
|
||||
return G_LIST_MODEL (flatten);
|
||||
@@ -225,7 +225,7 @@ list_model_for_properties (GObject *object,
|
||||
g_object_unref (tmp);
|
||||
}
|
||||
|
||||
result = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (concat)));
|
||||
result = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (concat)));
|
||||
g_object_unref (concat);
|
||||
return result;
|
||||
}
|
||||
@@ -330,7 +330,7 @@ object_tree_tree_view_get_children (GObject *object)
|
||||
g_object_unref (selection);
|
||||
g_list_store_append (result_list, columns);
|
||||
g_object_unref (columns);
|
||||
result = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list));
|
||||
result = gtk_flatten_list_model_new (G_LIST_MODEL (result_list));
|
||||
g_object_unref (result_list);
|
||||
|
||||
return G_LIST_MODEL (result);
|
||||
@@ -353,7 +353,7 @@ object_tree_column_view_get_children (GObject *object)
|
||||
g_list_store_append (result_list, sublist);
|
||||
g_object_unref (sublist);
|
||||
|
||||
result = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list));
|
||||
result = gtk_flatten_list_model_new (G_LIST_MODEL (result_list));
|
||||
g_object_unref (result_list);
|
||||
|
||||
return G_LIST_MODEL (result);
|
||||
@@ -640,7 +640,7 @@ object_get_children (GObject *object)
|
||||
|
||||
if (result_list)
|
||||
{
|
||||
result = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list)));
|
||||
result = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (result_list)));
|
||||
g_object_unref (result_list);
|
||||
}
|
||||
|
||||
@@ -1179,7 +1179,7 @@ create_root_model (GdkDisplay *display)
|
||||
g_list_store_append (list, special);
|
||||
g_object_unref (special);
|
||||
|
||||
filter = gtk_filter_list_model_new_for_type (G_TYPE_OBJECT);
|
||||
filter = gtk_filter_list_model_new (NULL, NULL);
|
||||
custom_filter = gtk_custom_filter_new (toplevel_filter_func,
|
||||
display, NULL);
|
||||
gtk_filter_list_model_set_filter (filter, custom_filter);
|
||||
@@ -1187,7 +1187,7 @@ create_root_model (GdkDisplay *display)
|
||||
g_list_store_append (list, filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
|
||||
flatten = gtk_flatten_list_model_new (G_LIST_MODEL (list));
|
||||
g_object_unref (list);
|
||||
return G_LIST_MODEL (flatten);
|
||||
}
|
||||
|
||||
@@ -371,6 +371,8 @@ gtk_public_sources = files([
|
||||
'gtkslicelistmodel.c',
|
||||
'gtksnapshot.c',
|
||||
'gtksorter.c',
|
||||
'gtksor2listmodel.c',
|
||||
'gtksor3listmodel.c',
|
||||
'gtksortlistmodel.c',
|
||||
'gtkspinbutton.c',
|
||||
'gtkspinner.c',
|
||||
@@ -640,6 +642,8 @@ gtk_public_headers = files([
|
||||
'gtkslicelistmodel.h',
|
||||
'gtksnapshot.h',
|
||||
'gtksorter.h',
|
||||
'gtksor2listmodel.h',
|
||||
'gtksor3listmodel.h',
|
||||
'gtksortlistmodel.h',
|
||||
'gtkspinbutton.h',
|
||||
'gtkspinner.h',
|
||||
|
||||
@@ -268,6 +268,7 @@ gtk/gtkscrolledwindow.c
|
||||
gtk/gtksearchbar.c
|
||||
gtk/gtksearchengine.c
|
||||
gtk/gtksearchentry.c
|
||||
gtk/gtkselectionfiltermodel.c
|
||||
gtk/gtkseparator.c
|
||||
gtk/gtksettings.c
|
||||
gtk/gtkshortcutaction.c
|
||||
|
||||
@@ -49,6 +49,7 @@ demos/gtk-demo/stack.ui
|
||||
demos/gtk-demo/themes.ui
|
||||
demos/gtk-demo/theming.ui
|
||||
demos/icon-browser/window.ui
|
||||
demos/node-editor/help-window.ui
|
||||
demos/node-editor/node-editor-window.ui
|
||||
demos/widget-factory/menus.ui
|
||||
demos/widget-factory/widget-factory.c
|
||||
@@ -90,7 +91,6 @@ gtk/inspector/actions.ui.h
|
||||
gtk/inspector/css-editor.ui
|
||||
gtk/inspector/css-editor.ui.h
|
||||
gtk/inspector/css-node-tree.ui
|
||||
gtk/inspector/data-list.ui
|
||||
gtk/inspector/data-list.ui.h
|
||||
gtk/inspector/general.ui
|
||||
gtk/inspector/general.ui.h
|
||||
@@ -116,6 +116,7 @@ gtk/inspector/statistics.ui
|
||||
gtk/inspector/statistics.ui.h
|
||||
gtk/inspector/style-prop-list.ui
|
||||
gtk/inspector/style-prop-list.ui.h
|
||||
gtk/inspector/tree-data.ui
|
||||
gtk/inspector/type-info.ui
|
||||
gtk/inspector/visual.ui
|
||||
gtk/inspector/visual.ui.h
|
||||
|
||||
+1989
-1418
File diff suppressed because it is too large
Load Diff
+416
-394
File diff suppressed because it is too large
Load Diff
+338
-339
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -270,6 +270,7 @@ gtk/gtkscrolledwindow.c
|
||||
gtk/gtksearchbar.c
|
||||
gtk/gtksearchengine.c
|
||||
gtk/gtksearchentry.c
|
||||
gtk/gtkselectionfiltermodel.c
|
||||
gtk/gtkseparator.c
|
||||
gtk/gtksettings.c
|
||||
gtk/gtkshortcutaction.c
|
||||
@@ -345,7 +346,6 @@ gtk/inspector/css-editor.c
|
||||
gtk/inspector/css-editor.ui
|
||||
gtk/inspector/css-node-tree.c
|
||||
gtk/inspector/css-node-tree.ui
|
||||
gtk/inspector/data-list.ui
|
||||
gtk/inspector/general.c
|
||||
gtk/inspector/general.ui
|
||||
gtk/inspector/inspect-button.c
|
||||
@@ -364,6 +364,7 @@ gtk/inspector/shortcuts.ui
|
||||
gtk/inspector/size-groups.c
|
||||
gtk/inspector/statistics.c
|
||||
gtk/inspector/statistics.ui
|
||||
gtk/inspector/tree-data.ui
|
||||
gtk/inspector/type-info.ui
|
||||
gtk/inspector/visual.c
|
||||
gtk/inspector/visual.ui
|
||||
|
||||
@@ -49,6 +49,7 @@ demos/gtk-demo/stack.ui
|
||||
demos/gtk-demo/themes.ui
|
||||
demos/gtk-demo/theming.ui
|
||||
demos/icon-browser/window.ui
|
||||
demos/node-editor/help-window.ui
|
||||
demos/node-editor/node-editor-window.ui
|
||||
demos/widget-factory/menus.ui
|
||||
demos/widget-factory/widget-factory.c
|
||||
|
||||
+4
-18
@@ -118,17 +118,6 @@ response_cb (GtkDialog *dialog,
|
||||
g_main_context_wakeup (NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
no_backup_files_filter (const GtkFileFilterInfo *filter_info,
|
||||
gpointer data)
|
||||
{
|
||||
gsize len = filter_info->display_name ? strlen (filter_info->display_name) : 0;
|
||||
if (len > 0 && filter_info->display_name[len - 1] == '~')
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
filter_changed (GtkFileChooserDialog *dialog,
|
||||
gpointer data)
|
||||
@@ -393,18 +382,13 @@ main (int argc, char **argv)
|
||||
|
||||
/* Make this filter the default */
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "No backup files");
|
||||
gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_DISPLAY_NAME,
|
||||
no_backup_files_filter, NULL, NULL);
|
||||
gtk_file_filter_add_mime_type (filter, "image/png");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "Starts with D");
|
||||
gtk_file_filter_add_pattern (filter, "D*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
g_signal_connect (dialog, "notify::filter",
|
||||
G_CALLBACK (filter_changed), NULL);
|
||||
@@ -414,11 +398,13 @@ main (int argc, char **argv)
|
||||
gtk_file_filter_add_mime_type (filter, "image/jpeg");
|
||||
gtk_file_filter_add_mime_type (filter, "image/png");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "Images");
|
||||
gtk_file_filter_add_pixbuf_formats (filter);
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
/* Choices */
|
||||
|
||||
|
||||
+14
-5
@@ -5672,15 +5672,19 @@ native_filter_changed (GtkWidget *combo,
|
||||
GtkFileChooserNative *native)
|
||||
{
|
||||
int i;
|
||||
GSList *filters, *l;
|
||||
GListModel *filters;
|
||||
GtkFileFilter *filter;
|
||||
|
||||
i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
|
||||
|
||||
filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (native));
|
||||
for (l = filters; l != NULL; l = l->next)
|
||||
gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (native), l->data);
|
||||
g_slist_free (filters);
|
||||
filters = gtk_file_chooser_get_filters (GTK_FILE_CHOOSER (native));
|
||||
while (g_list_model_get_n_items (filters) > 0)
|
||||
{
|
||||
GtkFileFilter *f = g_list_model_get_item (filters, 0);
|
||||
gtk_file_chooser_remove_filter (GTK_FILE_CHOOSER (native), f);
|
||||
g_object_unref (f);
|
||||
}
|
||||
g_object_unref (filters);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
@@ -5692,17 +5696,20 @@ native_filter_changed (GtkWidget *combo,
|
||||
gtk_file_filter_add_pattern (filter, "*.doc");
|
||||
gtk_file_filter_add_pattern (filter, "*.txt");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "Images");
|
||||
gtk_file_filter_add_pixbuf_formats (filter);
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "All");
|
||||
gtk_file_filter_add_pattern (filter, "*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
g_object_unref (filter);
|
||||
break;
|
||||
|
||||
case 2: /* mimetype */
|
||||
@@ -5710,12 +5717,14 @@ native_filter_changed (GtkWidget *combo,
|
||||
gtk_file_filter_set_name (filter, "Text");
|
||||
gtk_file_filter_add_mime_type (filter, "text/plain");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
g_object_unref (filter);
|
||||
|
||||
filter = gtk_file_filter_new ();
|
||||
gtk_file_filter_set_name (filter, "All");
|
||||
gtk_file_filter_add_pattern (filter, "*");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (native), filter);
|
||||
g_object_unref (filter);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
|
||||
@@ -621,7 +621,7 @@ main (int argc, char *argv[])
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_widget), NULL);
|
||||
listview = gtk_grid_view_new_with_factory (factory);
|
||||
listview = gtk_list_view_new_with_factory (factory);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
|
||||
if (argc > 1)
|
||||
@@ -645,7 +645,7 @@ main (int argc, char *argv[])
|
||||
selectionmodel = file_info_selection_new (G_LIST_MODEL (filter));
|
||||
g_object_unref (filter);
|
||||
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (listview), G_LIST_MODEL (selectionmodel));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selectionmodel));
|
||||
|
||||
statusbar = gtk_statusbar_new ();
|
||||
gtk_widget_add_tick_callback (statusbar, (GtkTickCallback) update_statusbar, NULL, NULL);
|
||||
|
||||
+15
-2
@@ -424,13 +424,13 @@ test_slice (void)
|
||||
|
||||
gtk_bitset_add_range (set, 10, 30);
|
||||
|
||||
gtk_bitset_slice (set, 20, 10, 20);
|
||||
gtk_bitset_splice (set, 20, 10, 20);
|
||||
|
||||
for (i = 0; i < 60; i++)
|
||||
g_assert_cmpint (gtk_bitset_contains (set, i), ==, (i >= 10 && i < 20) ||
|
||||
(i >= 40 && i < 50));
|
||||
|
||||
gtk_bitset_slice (set, 25, 10, 0);
|
||||
gtk_bitset_splice (set, 25, 10, 0);
|
||||
|
||||
for (i = 0; i < 60; i++)
|
||||
g_assert_cmpint (gtk_bitset_contains (set, i), ==, (i >= 10 && i < 20) ||
|
||||
@@ -543,6 +543,18 @@ test_iter (void)
|
||||
gtk_bitset_unref (set);
|
||||
}
|
||||
|
||||
static void
|
||||
test_splice_overflow (void)
|
||||
{
|
||||
GtkBitset *set, *compare;
|
||||
|
||||
set = gtk_bitset_new_range (3, 1);
|
||||
gtk_bitset_splice (set, 0, 0, 13);
|
||||
|
||||
compare = gtk_bitset_new_range (16, 1);
|
||||
g_assert_true (gtk_bitset_equals (set, compare));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -562,6 +574,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/bitset/slice", test_slice);
|
||||
g_test_add_func ("/bitset/rectangle", test_rectangle);
|
||||
g_test_add_func ("/bitset/iter", test_iter);
|
||||
g_test_add_func ("/bitset/splice-overflow", test_splice_overflow);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
+2
-12
@@ -2387,7 +2387,6 @@ test_file_filter (void)
|
||||
GtkBuilder *builder;
|
||||
GObject *obj;
|
||||
GtkFileFilter *filter;
|
||||
GtkFileFilterInfo info;
|
||||
|
||||
const gchar buffer[] =
|
||||
"<interface>"
|
||||
@@ -2409,17 +2408,8 @@ test_file_filter (void)
|
||||
g_assert (GTK_IS_FILE_FILTER (obj));
|
||||
filter = GTK_FILE_FILTER (obj);
|
||||
g_assert_cmpstr (gtk_file_filter_get_name (filter), ==, "Text and Images");
|
||||
g_assert (gtk_file_filter_get_needed (filter) & GTK_FILE_FILTER_MIME_TYPE);
|
||||
g_assert (gtk_file_filter_get_needed (filter) & GTK_FILE_FILTER_DISPLAY_NAME);
|
||||
|
||||
info.filename = "test1.txt";
|
||||
info.display_name = "test1.txt";
|
||||
info.contains = GTK_FILE_FILTER_FILENAME | GTK_FILE_FILTER_DISPLAY_NAME;
|
||||
g_assert (gtk_file_filter_filter (filter, &info));
|
||||
|
||||
info.mime_type = "application/x-pdf";
|
||||
info.contains = GTK_FILE_FILTER_MIME_TYPE;
|
||||
g_assert (!gtk_file_filter_filter (filter, &info));
|
||||
g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE));
|
||||
g_assert_true (g_strv_contains (gtk_file_filter_get_attributes (filter), G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME));
|
||||
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ test_bind_child (void)
|
||||
"filter");
|
||||
|
||||
filter = gtk_string_filter_new ();
|
||||
child = gtk_filter_list_model_new_for_type (G_TYPE_OBJECT);
|
||||
child = gtk_filter_list_model_new (NULL, NULL);
|
||||
gtk_filter_list_model_set_filter (child, filter);
|
||||
target = gtk_filter_list_model_new (G_LIST_MODEL (child), NULL);
|
||||
g_object_unref (child);
|
||||
|
||||
@@ -0,0 +1,479 @@
|
||||
/* GtkRBTree tests.
|
||||
*
|
||||
* Copyright (C) 2011, Red Hat, Inc.
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define ensure_updated() G_STMT_START{ \
|
||||
while (g_main_context_pending (NULL)) \
|
||||
g_main_context_iteration (NULL, TRUE); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_model_equal(model1, model2) G_STMT_START{ \
|
||||
guint _i, _n; \
|
||||
g_assert_cmpint (g_list_model_get_n_items (model1), ==, g_list_model_get_n_items (model2)); \
|
||||
_n = g_list_model_get_n_items (model1); \
|
||||
for (_i = 0; _i < _n; _i++) \
|
||||
{ \
|
||||
gpointer o1 = g_list_model_get_item (model1, _i); \
|
||||
gpointer o2 = g_list_model_get_item (model2, _i); \
|
||||
if (o1 != o2) \
|
||||
{ \
|
||||
char *_s = g_strdup_printf ("Objects differ at index %u out of %u", _i, _n); \
|
||||
g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, _s); \
|
||||
g_free (_s); \
|
||||
} \
|
||||
} \
|
||||
}G_STMT_END
|
||||
|
||||
G_GNUC_UNUSED static char *
|
||||
model_to_string (GListModel *model)
|
||||
{
|
||||
GString *string;
|
||||
guint i, n;
|
||||
|
||||
n = g_list_model_get_n_items (model);
|
||||
string = g_string_new (NULL);
|
||||
|
||||
/* Check that all unchanged items are indeed unchanged */
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (model, i);
|
||||
|
||||
if (i > 0)
|
||||
g_string_append (string, ", ");
|
||||
g_string_append (string, gtk_string_object_get_string (item));
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
assert_items_changed_correctly (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GListModel *compare)
|
||||
{
|
||||
guint i, n_items;
|
||||
|
||||
//g_print ("%s => %u -%u +%u => %s\n", model_to_string (compare), position, removed, added, model_to_string (model));
|
||||
|
||||
g_assert_cmpint (g_list_model_get_n_items (model), ==, g_list_model_get_n_items (compare) - removed + added);
|
||||
n_items = g_list_model_get_n_items (model);
|
||||
|
||||
/* Check that all unchanged items are indeed unchanged */
|
||||
for (i = 0; i < position; i++)
|
||||
{
|
||||
gpointer o1 = g_list_model_get_item (model, i);
|
||||
gpointer o2 = g_list_model_get_item (compare, i);
|
||||
g_assert_cmphex (GPOINTER_TO_SIZE (o1), ==, GPOINTER_TO_SIZE (o2));
|
||||
g_object_unref (o1);
|
||||
g_object_unref (o2);
|
||||
}
|
||||
for (i = position + added; i < n_items; i++)
|
||||
{
|
||||
gpointer o1 = g_list_model_get_item (model, i);
|
||||
gpointer o2 = g_list_model_get_item (compare, i - added + removed);
|
||||
g_assert_cmphex (GPOINTER_TO_SIZE (o1), ==, GPOINTER_TO_SIZE (o2));
|
||||
g_object_unref (o1);
|
||||
g_object_unref (o2);
|
||||
}
|
||||
|
||||
/* Check that the first and last added item are different from
|
||||
* first and last removed item.
|
||||
* Otherwise we could have kept them as-is
|
||||
*/
|
||||
if (removed > 0 && added > 0)
|
||||
{
|
||||
gpointer o1 = g_list_model_get_item (model, position);
|
||||
gpointer o2 = g_list_model_get_item (compare, position);
|
||||
g_assert_cmphex (GPOINTER_TO_SIZE (o1), !=, GPOINTER_TO_SIZE (o2));
|
||||
g_object_unref (o1);
|
||||
g_object_unref (o2);
|
||||
|
||||
o1 = g_list_model_get_item (model, position + added - 1);
|
||||
o2 = g_list_model_get_item (compare, position + removed - 1);
|
||||
g_assert_cmphex (GPOINTER_TO_SIZE (o1), !=, GPOINTER_TO_SIZE (o2));
|
||||
g_object_unref (o1);
|
||||
g_object_unref (o2);
|
||||
}
|
||||
|
||||
/* Finally, perform the same change as the signal indicates */
|
||||
g_list_store_splice (G_LIST_STORE (compare), position, removed, NULL, 0);
|
||||
for (i = position; i < position + added; i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (G_LIST_MODEL (model), i);
|
||||
g_list_store_insert (G_LIST_STORE (compare), i, item);
|
||||
g_object_unref (item);
|
||||
}
|
||||
}
|
||||
|
||||
static GtkFilterListModel *
|
||||
filter_list_model_new (GListModel *source,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
GtkFilterListModel *model;
|
||||
GListStore *check;
|
||||
guint i;
|
||||
|
||||
model = gtk_filter_list_model_new (source, filter);
|
||||
check = g_list_store_new (G_TYPE_OBJECT);
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i++)
|
||||
{
|
||||
gpointer item = g_list_model_get_item (G_LIST_MODEL (model), i);
|
||||
g_list_store_append (check, item);
|
||||
g_object_unref (item);
|
||||
}
|
||||
g_signal_connect_data (model,
|
||||
"items-changed",
|
||||
G_CALLBACK (assert_items_changed_correctly),
|
||||
check,
|
||||
(GClosureNotify) g_object_unref,
|
||||
0);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
#define N_MODELS 8
|
||||
|
||||
static GtkFilterListModel *
|
||||
create_filter_list_model (gconstpointer model_id,
|
||||
GListModel *source,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
GtkFilterListModel *model;
|
||||
guint id = GPOINTER_TO_UINT (model_id);
|
||||
|
||||
model = filter_list_model_new (id & 1 ? NULL : source, id & 2 ? NULL : filter);
|
||||
|
||||
switch (id >> 2)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gtk_filter_list_model_set_incremental (model, TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
if (id & 1)
|
||||
gtk_filter_list_model_set_model (model, source);
|
||||
if (id & 2)
|
||||
gtk_filter_list_model_set_filter (model, filter);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
create_source_model (guint min_size, guint max_size)
|
||||
{
|
||||
GtkStringList *list;
|
||||
guint i, size;
|
||||
|
||||
size = g_test_rand_int_range (min_size, max_size + 1);
|
||||
list = gtk_string_list_new (NULL);
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
gtk_string_list_append (list, g_test_rand_bit () ? "A" : "B");
|
||||
|
||||
return G_LIST_MODEL (list);
|
||||
}
|
||||
|
||||
#define N_FILTERS 5
|
||||
|
||||
static GtkFilter *
|
||||
create_filter (gsize id)
|
||||
{
|
||||
GtkFilter *filter;
|
||||
GtkExpression *expr;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
/* GTK_FILTER_MATCH_ALL */
|
||||
return gtk_string_filter_new ();
|
||||
|
||||
case 1:
|
||||
/* GTK_FILTER_MATCH_NONE */
|
||||
filter = gtk_string_filter_new ();
|
||||
gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "does not matter, because no expression");
|
||||
return filter;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
/* match all As, Bs and nothing */
|
||||
filter = gtk_string_filter_new ();
|
||||
expr = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string");
|
||||
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expr);
|
||||
gtk_expression_unref (expr);
|
||||
if (id == 2)
|
||||
gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "A");
|
||||
else if (id == 3)
|
||||
gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "B");
|
||||
else
|
||||
gtk_string_filter_set_search (GTK_STRING_FILTER (filter), "does-not-match");
|
||||
return filter;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkFilter *
|
||||
create_random_filter (gboolean allow_null)
|
||||
{
|
||||
guint n;
|
||||
|
||||
if (allow_null)
|
||||
n = g_test_rand_int_range (0, N_FILTERS + 1);
|
||||
else
|
||||
n = g_test_rand_int_range (0, N_FILTERS);
|
||||
|
||||
if (n >= N_FILTERS)
|
||||
return NULL;
|
||||
|
||||
return create_filter (n);
|
||||
}
|
||||
|
||||
static void
|
||||
test_no_filter (gconstpointer model_id)
|
||||
{
|
||||
GtkFilterListModel *model;
|
||||
GListModel *source;
|
||||
GtkFilter *filter;
|
||||
|
||||
source = create_source_model (10, 10);
|
||||
model = create_filter_list_model (model_id, source, NULL);
|
||||
ensure_updated ();
|
||||
assert_model_equal (G_LIST_MODEL (model), source);
|
||||
|
||||
filter = create_random_filter (FALSE);
|
||||
gtk_filter_list_model_set_filter (model, filter);
|
||||
g_object_unref (filter);
|
||||
gtk_filter_list_model_set_filter (model, NULL);
|
||||
ensure_updated ();
|
||||
assert_model_equal (G_LIST_MODEL (model), source);
|
||||
|
||||
g_object_unref (model);
|
||||
g_object_unref (source);
|
||||
}
|
||||
|
||||
/* Compare this:
|
||||
* source => filter1 => filter2
|
||||
* with:
|
||||
* source => multifilter(filter1, filter2)
|
||||
* and randomly change the source and filters and see if the
|
||||
* two continue agreeing.
|
||||
*/
|
||||
static void
|
||||
test_two_filters (gconstpointer model_id)
|
||||
{
|
||||
GtkFilterListModel *compare;
|
||||
GtkFilterListModel *model1, *model2;
|
||||
GListModel *source;
|
||||
GtkFilter *every, *filter;
|
||||
guint i, j, k;
|
||||
|
||||
source = create_source_model (10, 10);
|
||||
model1 = create_filter_list_model (model_id, source, NULL);
|
||||
model2 = create_filter_list_model (model_id, G_LIST_MODEL (model1), NULL);
|
||||
every = gtk_every_filter_new ();
|
||||
compare = create_filter_list_model (model_id, source, every);
|
||||
g_object_unref (every);
|
||||
g_object_unref (source);
|
||||
|
||||
for (i = 0; i < N_FILTERS; i++)
|
||||
{
|
||||
filter = create_filter (i);
|
||||
gtk_filter_list_model_set_filter (model1, filter);
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (every), filter);
|
||||
|
||||
for (j = 0; j < N_FILTERS; j++)
|
||||
{
|
||||
filter = create_filter (i);
|
||||
gtk_filter_list_model_set_filter (model2, filter);
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (every), filter);
|
||||
|
||||
ensure_updated ();
|
||||
assert_model_equal (G_LIST_MODEL (model2), G_LIST_MODEL (compare));
|
||||
|
||||
for (k = 0; k < 10; k++)
|
||||
{
|
||||
source = create_source_model (0, 20);
|
||||
gtk_filter_list_model_set_model (compare, source);
|
||||
gtk_filter_list_model_set_model (model1, source);
|
||||
g_object_unref (source);
|
||||
|
||||
ensure_updated ();
|
||||
assert_model_equal (G_LIST_MODEL (model2), G_LIST_MODEL (compare));
|
||||
}
|
||||
|
||||
gtk_multi_filter_remove (GTK_MULTI_FILTER (every), 1);
|
||||
}
|
||||
|
||||
gtk_multi_filter_remove (GTK_MULTI_FILTER (every), 0);
|
||||
}
|
||||
|
||||
g_object_unref (compare);
|
||||
g_object_unref (model2);
|
||||
g_object_unref (model1);
|
||||
}
|
||||
|
||||
/* Compare this:
|
||||
* (source => filter) * => flatten
|
||||
* with:
|
||||
* source * => flatten => filter
|
||||
* and randomly add/remove sources and change the filters and
|
||||
* see if the two agree.
|
||||
*
|
||||
* We use a multifilter for the top chain so that changing the filter
|
||||
* is easy.
|
||||
*/
|
||||
static void
|
||||
test_model_changes (gconstpointer model_id)
|
||||
{
|
||||
GListStore *store1, *store2;
|
||||
GtkFlattenListModel *flatten1, *flatten2;
|
||||
GtkFilterListModel *model2;
|
||||
GtkFilter *multi, *filter;
|
||||
gsize i;
|
||||
|
||||
filter = create_random_filter (TRUE);
|
||||
multi = gtk_every_filter_new ();
|
||||
if (filter)
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (multi), filter);
|
||||
|
||||
store1 = g_list_store_new (G_TYPE_OBJECT);
|
||||
store2 = g_list_store_new (G_TYPE_OBJECT);
|
||||
flatten1 = gtk_flatten_list_model_new (G_LIST_MODEL (store1));
|
||||
flatten2 = gtk_flatten_list_model_new (G_LIST_MODEL (store2));
|
||||
model2 = create_filter_list_model (model_id, G_LIST_MODEL (flatten2), filter);
|
||||
|
||||
for (i = 0; i < 500; i++)
|
||||
{
|
||||
gboolean add = FALSE, remove = FALSE;
|
||||
guint position;
|
||||
|
||||
switch (g_test_rand_int_range (0, 4))
|
||||
{
|
||||
case 0:
|
||||
/* change the filter */
|
||||
filter = create_random_filter (TRUE);
|
||||
gtk_multi_filter_remove (GTK_MULTI_FILTER (multi), 0); /* no-op if no filter */
|
||||
if (filter)
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (multi), filter);
|
||||
gtk_filter_list_model_set_filter (model2, filter);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* remove a model */
|
||||
remove = TRUE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* add a model */
|
||||
add = TRUE;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
/* replace a model */
|
||||
remove = TRUE;
|
||||
add = TRUE;
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
position = g_test_rand_int_range (0, g_list_model_get_n_items (G_LIST_MODEL (store1)) + 1);
|
||||
if (g_list_model_get_n_items (G_LIST_MODEL (store1)) == position)
|
||||
remove = FALSE;
|
||||
|
||||
if (add)
|
||||
{
|
||||
/* We want at least one element, otherwise the filters will see no changes */
|
||||
GListModel *source = create_source_model (1, 20);
|
||||
GtkFilterListModel *model1 = create_filter_list_model (model_id, source, multi);
|
||||
g_list_store_splice (store1,
|
||||
position,
|
||||
remove ? 1 : 0,
|
||||
(gpointer *) &model1, 1);
|
||||
g_list_store_splice (store2,
|
||||
position,
|
||||
remove ? 1 : 0,
|
||||
(gpointer *) &source, 1);
|
||||
g_object_unref (source);
|
||||
}
|
||||
else if (remove)
|
||||
{
|
||||
g_list_store_remove (store1, position);
|
||||
g_list_store_remove (store2, position);
|
||||
}
|
||||
|
||||
if (g_test_rand_bit ())
|
||||
{
|
||||
ensure_updated ();
|
||||
assert_model_equal (G_LIST_MODEL (flatten1), G_LIST_MODEL (model2));
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (model2);
|
||||
g_object_unref (flatten2);
|
||||
g_object_unref (flatten1);
|
||||
g_object_unref (store2);
|
||||
g_object_unref (store1);
|
||||
g_object_unref (multi);
|
||||
}
|
||||
|
||||
static void
|
||||
add_test_for_all_models (const char *name,
|
||||
GTestDataFunc test_func)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < N_MODELS; i++)
|
||||
{
|
||||
char *path = g_strdup_printf ("/filterlistmodel/model%u/%s", i, name);
|
||||
g_test_add_data_func (path, GUINT_TO_POINTER (i), test_func);
|
||||
g_free (path);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
setlocale (LC_ALL, "C");
|
||||
|
||||
add_test_for_all_models ("no-filter", test_no_filter);
|
||||
add_test_for_all_models ("two-filters", test_two_filters);
|
||||
add_test_for_all_models ("model-changes", test_model_changes);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -210,7 +210,7 @@ new_model (GListStore *store)
|
||||
GtkFlattenListModel *result;
|
||||
GString *changes;
|
||||
|
||||
result = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (store));
|
||||
result = gtk_flatten_list_model_new (G_LIST_MODEL (store));
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
|
||||
|
||||
@@ -196,7 +196,7 @@ new_model (GListStore *store)
|
||||
GtkMapListModel *result;
|
||||
GString *changes;
|
||||
|
||||
result = gtk_map_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (store), map_multiply, GUINT_TO_POINTER (2), NULL);
|
||||
result = gtk_map_list_model_new (G_LIST_MODEL (store), map_multiply, GUINT_TO_POINTER (2), NULL);
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
|
||||
|
||||
@@ -30,6 +30,7 @@ tests = [
|
||||
['expression'],
|
||||
['filter'],
|
||||
['filterlistmodel'],
|
||||
['filterlistmodel-exhaustive'],
|
||||
['flattenlistmodel'],
|
||||
['floating'],
|
||||
['flowbox'],
|
||||
@@ -74,6 +75,8 @@ tests = [
|
||||
['typename'],
|
||||
['displayclose'],
|
||||
['revealer-size'],
|
||||
['vector'],
|
||||
['vector-performance'],
|
||||
['widgetorder'],
|
||||
['widget-refcount'],
|
||||
]
|
||||
|
||||
@@ -613,6 +613,59 @@ test_selection_filter (void)
|
||||
g_object_unref (store);
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
static void
|
||||
test_set_model (void)
|
||||
{
|
||||
GtkSelectionModel *selection;
|
||||
GListStore *store;
|
||||
GListModel *m1, *m2;
|
||||
gboolean ret;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
m1 = G_LIST_MODEL (store);
|
||||
m2 = G_LIST_MODEL (gtk_slice_list_model_new (m1, 0, 3));
|
||||
selection = new_model (store);
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
ret = gtk_selection_model_select_range (selection, 1, 3, FALSE);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "2 3 4");
|
||||
assert_selection_changes (selection, "1:3");
|
||||
|
||||
/* we retain the selected item across model changes */
|
||||
gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
|
||||
assert_changes (selection, "0-5+3");
|
||||
assert_selection (selection, "2 3");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), NULL);
|
||||
assert_changes (selection, "0-3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m2);
|
||||
assert_changes (selection, "0+3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
ret = gtk_selection_model_select_all (selection);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "1 2 3");
|
||||
assert_selection_changes (selection, "0:3");
|
||||
|
||||
/* we retain no selected item across model changes */
|
||||
gtk_multi_selection_set_model (GTK_MULTI_SELECTION (selection), m1);
|
||||
assert_changes (selection, "0-3+5");
|
||||
assert_selection (selection, "1 2 3");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_object_unref (m2);
|
||||
g_object_unref (m1);
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -633,6 +686,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/multiselection/readd", test_readd);
|
||||
g_test_add_func ("/multiselection/set_selection", test_set_selection);
|
||||
g_test_add_func ("/multiselection/selection-filter", test_selection_filter);
|
||||
g_test_add_func ("/multiselection/set-model", test_set_model);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -644,6 +644,57 @@ test_query_range (void)
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
static void
|
||||
test_set_model (void)
|
||||
{
|
||||
GtkSelectionModel *selection;
|
||||
GListStore *store;
|
||||
GListModel *m1, *m2;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
m1 = G_LIST_MODEL (store);
|
||||
m2 = G_LIST_MODEL (gtk_slice_list_model_new (m1, 0, 3));
|
||||
selection = new_model (store, TRUE, TRUE);
|
||||
assert_selection (selection, "1");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
/* we retain the selected item across model changes */
|
||||
gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
|
||||
assert_changes (selection, "0-5+3");
|
||||
assert_selection (selection, "1");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), NULL);
|
||||
assert_changes (selection, "0-3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
|
||||
gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
|
||||
assert_changes (selection, "0+3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
/* we retain no selected item across model changes */
|
||||
gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m1);
|
||||
assert_changes (selection, "0-3+5");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (selection), 4);
|
||||
assert_selection (selection, "5");
|
||||
assert_selection_changes (selection, "4:1");
|
||||
|
||||
gtk_single_selection_set_model (GTK_SINGLE_SELECTION (selection), m2);
|
||||
assert_changes (selection, "0-5+3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_object_unref (m2);
|
||||
g_object_unref (m1);
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -662,6 +713,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/singleselection/persistence", test_persistence);
|
||||
g_test_add_func ("/singleselection/query-range", test_query_range);
|
||||
g_test_add_func ("/singleselection/changes", test_changes);
|
||||
g_test_add_func ("/singleselection/set-model", test_set_model);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -191,11 +191,7 @@ new_model (GListStore *store, guint offset, guint size)
|
||||
GtkSliceListModel *result;
|
||||
GString *changes;
|
||||
|
||||
result = gtk_slice_list_model_new_for_type (G_TYPE_OBJECT);
|
||||
if (store)
|
||||
gtk_slice_list_model_set_model (result, G_LIST_MODEL (store));
|
||||
gtk_slice_list_model_set_offset (result, offset);
|
||||
gtk_slice_list_model_set_size (result, size);
|
||||
result = gtk_slice_list_model_new (G_LIST_MODEL (store), offset, size);
|
||||
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
|
||||
@@ -203,7 +203,7 @@ new_model (gpointer model)
|
||||
g_object_unref (sorter);
|
||||
}
|
||||
else
|
||||
result = gtk_sort_list_model_new_for_type (G_TYPE_OBJECT);
|
||||
result = gtk_sort_list_model_new (NULL, NULL);
|
||||
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
|
||||
@@ -184,7 +184,7 @@ test_splice (void)
|
||||
|
||||
assert_model (list, "a b c d e");
|
||||
|
||||
gtk_string_list_splice (list, 2, 2, (const char *[]){ "x", "y", "z" }, 3);
|
||||
gtk_string_list_splice (list, 2, 2, (const char *[]){ "x", "y", "z", NULL });
|
||||
|
||||
assert_model (list, "a b x y z e");
|
||||
assert_changes (list, "2-2+3");
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#define GTK_VECTOR_NAME pointer_vector
|
||||
#define GTK_VECTOR_TYPE_NAME PointerVector
|
||||
#include "../../gtk/gtkvectorimpl.c"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#define GTK_VECTOR_NAME prealloc_vector
|
||||
#define GTK_VECTOR_TYPE_NAME PreallocVector
|
||||
#define GTK_VECTOR_PREALLOC 1024
|
||||
#include "../../gtk/gtkvectorimpl.c"
|
||||
|
||||
static inline guint
|
||||
quick_random (guint prev)
|
||||
{
|
||||
prev ^= prev << 13;
|
||||
prev ^= prev >> 17;
|
||||
prev ^= prev << 5;
|
||||
return prev;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
gsize stack_space;
|
||||
gpointer (* create) (gpointer space, gsize size);
|
||||
void (* free) (gpointer array);
|
||||
void (* reserve) (gpointer array, gsize size);
|
||||
gpointer (* get) (gpointer array, gsize pos);
|
||||
void (* append) (gpointer array, gpointer data);
|
||||
void (* insert) (gpointer array, gsize pos, gpointer data);
|
||||
} Array;
|
||||
|
||||
static gpointer
|
||||
create_ptrarray (gpointer space,
|
||||
gsize size)
|
||||
{
|
||||
return g_ptr_array_sized_new (size);
|
||||
}
|
||||
|
||||
static void
|
||||
free_ptrarray (gpointer array)
|
||||
{
|
||||
g_ptr_array_free (array, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
reserve_ptrarray (gpointer array,
|
||||
gsize size)
|
||||
{
|
||||
gsize length = ((GPtrArray *) array)->len;
|
||||
|
||||
if (length >= size)
|
||||
return;
|
||||
|
||||
g_ptr_array_set_size (array, size);
|
||||
g_ptr_array_set_size (array, length);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
get_ptrarray (gpointer array,
|
||||
gsize pos)
|
||||
{
|
||||
return g_ptr_array_index ((GPtrArray *) array, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
append_ptrarray (gpointer array,
|
||||
gpointer data)
|
||||
{
|
||||
g_ptr_array_add (array, data);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_ptrarray (gpointer array,
|
||||
gsize pos,
|
||||
gpointer data)
|
||||
{
|
||||
g_ptr_array_insert (array, pos, data);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
create_vector (gpointer space,
|
||||
gsize size)
|
||||
{
|
||||
pointer_vector_init (space);
|
||||
|
||||
if (size)
|
||||
pointer_vector_reserve ((PointerVector *) space, size);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
free_vector (gpointer array)
|
||||
{
|
||||
pointer_vector_clear (array);
|
||||
}
|
||||
|
||||
static void
|
||||
reserve_vector (gpointer array,
|
||||
gsize size)
|
||||
{
|
||||
pointer_vector_reserve (array, size);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
get_vector (gpointer array,
|
||||
gsize pos)
|
||||
{
|
||||
return pointer_vector_get (array, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
append_vector (gpointer array,
|
||||
gpointer data)
|
||||
{
|
||||
pointer_vector_append (array, data);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_vector (gpointer array,
|
||||
gsize pos,
|
||||
gpointer data)
|
||||
{
|
||||
pointer_vector_splice (array, pos, 0, &data, 1);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
create_prealloc (gpointer space,
|
||||
gsize size)
|
||||
{
|
||||
prealloc_vector_init (space);
|
||||
|
||||
if (size)
|
||||
prealloc_vector_reserve ((PreallocVector *) space, size);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
free_prealloc (gpointer array)
|
||||
{
|
||||
prealloc_vector_clear (array);
|
||||
}
|
||||
|
||||
static void
|
||||
reserve_prealloc (gpointer array,
|
||||
gsize size)
|
||||
{
|
||||
prealloc_vector_reserve (array, size);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
get_prealloc (gpointer array,
|
||||
gsize pos)
|
||||
{
|
||||
return prealloc_vector_get (array, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
append_prealloc (gpointer array,
|
||||
gpointer data)
|
||||
{
|
||||
prealloc_vector_append (array, data);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_prealloc (gpointer array,
|
||||
gsize pos,
|
||||
gpointer data)
|
||||
{
|
||||
prealloc_vector_splice (array, pos, 0, &data, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
do_random_access (const Array *klass,
|
||||
guint random,
|
||||
gsize size,
|
||||
gsize max_size)
|
||||
{
|
||||
gpointer stack;
|
||||
gpointer array;
|
||||
guint i;
|
||||
guint position;
|
||||
gint64 start, end;
|
||||
guint iterations = 10000000;
|
||||
|
||||
size = pow (100 * 100 * 100 * 100, (double) size / max_size);
|
||||
|
||||
if (klass->stack_space)
|
||||
stack = g_alloca (klass->stack_space);
|
||||
else
|
||||
stack = NULL;
|
||||
array = klass->create (stack, size);
|
||||
for (i = 0; i < size; i++)
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
position = random % size;
|
||||
random = quick_random (random);
|
||||
g_assert_cmpint (position, ==, GPOINTER_TO_SIZE (klass->get (array, position)));
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
g_print ("\"random access\",\"%s\", %zu, %g\n",
|
||||
klass->name,
|
||||
size,
|
||||
((double)(end - start)) / iterations);
|
||||
|
||||
klass->free (array);
|
||||
}
|
||||
|
||||
static void
|
||||
do_linear_access (const Array *klass,
|
||||
guint random,
|
||||
gsize size,
|
||||
gsize max_size)
|
||||
{
|
||||
gpointer stack;
|
||||
gpointer array;
|
||||
guint i;
|
||||
gint64 start, end;
|
||||
guint iterations = 1000000;
|
||||
|
||||
size = pow (100 * 100 * 100 * 100, (double) size / max_size);
|
||||
|
||||
if (klass->stack_space)
|
||||
stack = g_alloca (klass->stack_space);
|
||||
else
|
||||
stack = NULL;
|
||||
array = klass->create (stack, size);
|
||||
for (i = 0; i < size; i++)
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
g_assert_cmpint (i % size, ==, GPOINTER_TO_SIZE (klass->get (array, i % size)));
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
g_print ("\"linear access\", \"%s\", %zu, %g\n",
|
||||
klass->name,
|
||||
size,
|
||||
((double)(end - start)) / iterations);
|
||||
|
||||
klass->free (array);
|
||||
}
|
||||
|
||||
static void
|
||||
do_append (const Array *klass,
|
||||
guint random,
|
||||
gsize size,
|
||||
gsize max_size)
|
||||
{
|
||||
gpointer stack;
|
||||
gpointer array;
|
||||
guint i;
|
||||
gint64 start, end;
|
||||
int iterations = 10000;
|
||||
|
||||
size = pow (100 * 1000 * 1000, (double) size / max_size);
|
||||
|
||||
if (klass->stack_space)
|
||||
stack = g_alloca (klass->stack_space);
|
||||
else
|
||||
stack = NULL;
|
||||
array = klass->create (stack, size);
|
||||
for (i = 0; i < size; i++)
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = size; i < size + iterations; i++)
|
||||
{
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
klass->free (array);
|
||||
|
||||
g_print ("\"append\", \"%s\", %zu, %g\n",
|
||||
klass->name,
|
||||
size,
|
||||
((double) (end - start)) / iterations);
|
||||
}
|
||||
|
||||
static void
|
||||
do_insert (const Array *klass,
|
||||
guint random,
|
||||
gsize size,
|
||||
gsize max_size)
|
||||
{
|
||||
gpointer stack;
|
||||
gpointer array;
|
||||
guint i;
|
||||
gint64 start, end;
|
||||
int iterations = 10000;
|
||||
|
||||
size = pow (25 * 25 * 25 * 25, (double) size / max_size);
|
||||
|
||||
if (klass->stack_space)
|
||||
stack = g_alloca (klass->stack_space);
|
||||
else
|
||||
stack = NULL;
|
||||
array = klass->create (stack, size);
|
||||
for (i = 0; i < size; i++)
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = size; i < size + iterations; i++)
|
||||
{
|
||||
gsize position = random % size;
|
||||
random = quick_random (random);
|
||||
|
||||
klass->insert (array, position, GSIZE_TO_POINTER (i));
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
klass->free (array);
|
||||
|
||||
g_print ("\"insert\", \"%s\", %zu, %g\n",
|
||||
klass->name,
|
||||
size,
|
||||
((double) (end - start)) / iterations);
|
||||
}
|
||||
|
||||
static void
|
||||
do_create (const Array *klass,
|
||||
guint random,
|
||||
gsize size,
|
||||
gsize max_size)
|
||||
{
|
||||
gpointer stack;
|
||||
gpointer array;
|
||||
gsize i, j;
|
||||
gint64 start, end;
|
||||
gsize iterations = 100000;
|
||||
|
||||
size = pow (4 * 4 * 4 * 4, (double) size / max_size);
|
||||
|
||||
if (klass->stack_space)
|
||||
stack = g_alloca (klass->stack_space);
|
||||
else
|
||||
stack = NULL;
|
||||
|
||||
start = g_get_monotonic_time ();
|
||||
|
||||
for (i = 0; i < iterations; i++)
|
||||
{
|
||||
gsize position = random % size;
|
||||
random = quick_random (random);
|
||||
|
||||
array = klass->create (stack, size);
|
||||
for (j = 0; j < size; j++)
|
||||
klass->append (array, GSIZE_TO_POINTER (i));
|
||||
|
||||
klass->insert (array, position, GSIZE_TO_POINTER (i));
|
||||
klass->free (array);
|
||||
}
|
||||
|
||||
end = g_get_monotonic_time ();
|
||||
|
||||
g_print ("\"create\", \"%s\", %zu, %g\n",
|
||||
klass->name,
|
||||
size,
|
||||
((double) (end - start)) / iterations);
|
||||
}
|
||||
|
||||
const Array all_arrays[] = {
|
||||
{
|
||||
"ptrarray",
|
||||
0,
|
||||
create_ptrarray,
|
||||
free_ptrarray,
|
||||
reserve_ptrarray,
|
||||
get_ptrarray,
|
||||
append_ptrarray,
|
||||
insert_ptrarray
|
||||
},
|
||||
{
|
||||
"vector",
|
||||
sizeof (PointerVector),
|
||||
create_vector,
|
||||
free_vector,
|
||||
reserve_vector,
|
||||
get_vector,
|
||||
append_vector,
|
||||
insert_vector
|
||||
},
|
||||
{
|
||||
"preallocated-vector",
|
||||
sizeof (PreallocVector),
|
||||
create_prealloc,
|
||||
free_prealloc,
|
||||
reserve_prealloc,
|
||||
get_prealloc,
|
||||
append_prealloc,
|
||||
insert_prealloc
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
run_test (void (* test_func) (const Array *klass, guint random, gsize size, gsize max_size))
|
||||
{
|
||||
int max_size = 4;
|
||||
int size;
|
||||
int i;
|
||||
guint random = g_random_int ();
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (all_arrays); i++)
|
||||
{
|
||||
for (size = 1; size <= max_size; size++)
|
||||
{
|
||||
test_func (&all_arrays[i], random, size, max_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
g_print ("\"test\",\"model\",\"model size\",\"time\"\n");
|
||||
run_test (do_random_access);
|
||||
run_test (do_linear_access);
|
||||
run_test (do_append);
|
||||
run_test (do_insert);
|
||||
run_test (do_create);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 ();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user