Compare commits

...

78 Commits

Author SHA1 Message Date
Matthias Clasen 1e1d8cac0e wip: incremental sort 2020-07-07 22:10:01 -04:00
Benjamin Otte 7f54cf6294 gtk: Add a different sortmodel implementation
This is the dumbest possible sortmodel using an array:
Just grab all the items, put them in the array, qsort() the array.
2020-07-07 19:05:38 +02:00
Benjamin Otte 6e0839a956 demo: Add faster sorters
This is just the existing sorters, but without the overhead of GObject
properties.
2020-07-07 19:05:06 +02:00
Benjamin Otte abd9a19a94 sorter: Remove a return_if_fail()
It's too expsensive.
2020-07-07 19:02:29 +02:00
Benjamin Otte 1f0ace7454 xxx: vector_set_size 2020-07-07 15:34:43 +02:00
Benjamin Otte 802c99d4b4 testsuite: Add some vector performance tests
They're not very conclusive though, because the testing isn't
fine-grained enough for these microbenchmarks.
2020-07-07 02:23:09 +02:00
Benjamin Otte 173534710a snapshot: Use GtkVector for the state stack 2020-07-07 02:23:09 +02:00
Benjamin Otte 347959a112 vector: Add a bunch of new features
* GTK_VECTOR_BY_VALUE
   #define this to get GArrray-like behavior
 * gtk_vector_splice (v, 0, 0, NULL, 25)
   Adding items but passing NULL as the items will zero() them.
 * gtk_vector_set_size()
   A nicer way to call gtk_vector_splice()
2020-07-07 02:23:09 +02:00
Benjamin Otte 1ae939cf5a icontheme: Use GtkVector 2020-07-07 02:23:09 +02:00
Benjamin Otte edf523fe30 vector: Add null-termination 2020-07-07 02:23:09 +02:00
Benjamin Otte bfe2970a98 snapshot: Port node list to vector 2020-07-07 02:23:09 +02:00
Benjamin Otte c7749b9098 snapshot: Move structs into .c file
They aren't used anywhere else.
2020-07-07 02:23:09 +02:00
Benjamin Otte 2226fe0fca Remove preallocated array code
Now with GtkVector, we can use that one instead.
2020-07-07 02:23:09 +02:00
Benjamin Otte cbf9375f97 main: Use a GtkVector 2020-07-07 02:23:09 +02:00
Benjamin Otte 5297eb36b9 cssselector: Use GtkVector 2020-07-07 02:23:09 +02:00
Benjamin Otte b69e7777cd Add GtkVector
This is a scary idea where you #define a bunch of preprocessor values
and then #include "gtkvectorimpl.c" and end up with a dynamic array for
that data type.
2020-07-07 02:23:09 +02:00
Daniel Șerbănescu 817da34f7e Update Romanian translation 2020-07-06 20:41:16 +00:00
Daniel Șerbănescu 8fa44fc3e6 Update Romanian translation 2020-07-06 20:38:44 +00:00
Jordi Mas c7e94151b2 Update Catalan translation 2020-07-06 22:35:10 +02:00
Matthias Clasen 729ba44297 Merge branch 'wip/otte/filterlistmodel' into 'master'
Improve GtkFilterListModel

See merge request GNOME/gtk!2199
2020-07-06 15:42:44 +00:00
Matthias Clasen 2a2a6879c5 Merge branch 'file-chooser-api-cleanups' into 'master'
File chooser api cleanups

See merge request GNOME/gtk!2195
2020-07-06 15:41:56 +00:00
Matthias Clasen e7b773b031 filechooser: Add a readonly :shortcut-folders property
This makes the shortcut folders list accessible in the
the inspector.
2020-07-06 11:03:48 -04:00
Matthias Clasen 57a225681c filechooser: Add gtk_file_chooser_get_shortcuts
Replace gtk_file_chooser_list_shortcuts with a new
api that returns a list model.

Update all callers.
2020-07-06 11:03:48 -04:00
Matthias Clasen ea07a92366 filechooser: Add a readonly :filters property
This makes the filters list accessible in the
the inspector.
2020-07-06 11:03:48 -04:00
Matthias Clasen 76290e8ddb filechooser: Add gtk_file_chooser_get_filters
Replace gtk_file_chooser_list_filters with a new
api that returns a list model.

Update all callers.
2020-07-06 10:36:35 -04:00
Jordi Mas 26d83b1ab7 Update Catalan translation 2020-07-06 09:41:45 +02:00
Jordi Mas 2bba856206 Update Catalan translation 2020-07-06 08:54:41 +02:00
Benjamin Otte bf3382a89e testsuite: Add more filterlistmodel tests
These ones try to be exhaustive and randomly catch weird cases.

As such, the tests are more complicated and harder to grasp.
Sorry.
2020-07-06 03:42:43 +02:00
Benjamin Otte 3162e25671 bitset: Fix typo: gtk_bitset_slice() => gtk_bitset_splice() 2020-07-06 03:42:43 +02:00
Benjamin Otte 3d931b4fe2 bitset: Don't overflow when splicing
Testcase added.
2020-07-06 03:42:43 +02:00
Matthias Clasen fc770a383a gtk-demo: Use a progressbar in the words demo
This looks better and a bit more polished.
2020-07-06 03:42:43 +02:00
Matthias Clasen 62c385a9dd gtk-demo: No selection in the words demo
This demo is about filtering, not about selection,
so use a GtkNoSelection.
2020-07-06 03:42:43 +02:00
Matthias Clasen 7c4ad1a5c4 gtk-demo: Cosmetic fixes for the words demo
Set a window size, and don't put newlines in titles, left align and
ellipsize the label.
2020-07-06 03:42:43 +02:00
Benjamin Otte ac524bb13a demo: Make words listview load async
And add an "Open" button (why are filechooser buttons such a catastrophe
that I can't make them smaller?).
2020-07-06 03:42:43 +02:00
Benjamin Otte 66fa9380b5 filterlistmodel: Look at type of change
This way we can avoid refiltering most of an already filtered list when
the change becomes more strict.
2020-07-06 03:42:43 +02:00
Benjamin Otte b64eb6ca13 gtk-demo: Add incremental filtering to words demo 2020-07-06 03:42:43 +02:00
Benjamin Otte 9b2d8ac362 filterlistmodel: Add gtk_filter_list_model_get_pending()
This allows tracking if the model is busy filtering.
2020-07-06 03:42:43 +02:00
Benjamin Otte 2a90bc1a9b filterlistmodel: Add incremental filtering 2020-07-06 03:42:43 +02:00
Benjamin Otte d4b868d9bc filterlistmodel: Rewrite with bitset data structure
Bitsets are more powerful, less memory intensive and faster than the old
GtkRbTree version.
2020-07-06 03:42:43 +02:00
Benjamin Otte b54f6710a7 gtk-demo: Add a listview demo for filtering strings 2020-07-06 03:42:42 +02:00
Matthias Clasen 6bb7caf155 Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master

See merge request GNOME/gtk!2198
2020-07-06 00:42:14 +00:00
Matthias Clasen 202348f9d0 filefilter: Cosmetics
Various cleanups to make this code look less ancient.
2020-07-05 19:54:57 -04:00
Matthias Clasen 1a613de2f6 filefilter: Cosmetics 2020-07-05 19:54:20 -04:00
Matthias Clasen 665df37703 filefilter: Header file cosmetics 2020-07-05 19:36:45 -04:00
Matthias Clasen acad5e4e3d filefilter: Fix an embarrassing oversight
I forgot to remove some dead code, and left the
pixbuf_formats list in the rule union. Oops.
2020-07-05 19:32:36 -04:00
Matthias Clasen 6267c8469b Merge branch 'file-filter2' into 'master'
Make GtkFileFilter a GtkFilter

See merge request GNOME/gtk!2190
2020-07-05 20:32:05 +00:00
Matthias Clasen 5a2f791bdd filefilter: Cleanups and optimizations
Make mime-type rules hold multiple types. Store the
content types, so we don't have to do mime-type -> content-type
conversion in the match function. Store content types for the
pixbuf-formats rule as well, so we can avoid memory allocation
in the match function altogether.
2020-07-05 15:12:07 -04:00
Matthias Clasen 286a00a1db docs: Cleanups for the file filter docs
Now that GtkFileFilter is a GtkFilter, move it to the
filter section of the docs. While we are at it, touch
up the docs in some places.
2020-07-05 15:10:18 -04:00
Matthias Clasen 11dd602b28 Drop gtk_file_filter_filter
It has been superseded by gtk_filter_match.
2020-07-05 15:10:18 -04:00
Matthias Clasen 35988d659d Stop using gtk_file_filter_filter
Make all users of GtkFileFilter use it via the
GtkFilter api. This is in preparation for dropping
gtk_filter_filter_filter.
2020-07-05 15:10:18 -04:00
Matthias Clasen be3449b3ce filefilter: Convert to a GtkFilter
Make GtkFileFilter implement GtkFilter.
2020-07-05 15:10:18 -04:00
Matthias Clasen 2d8fddc1e9 filefilter: Drop GtkFileFilterFlags
Replace gtk_file_filter_get_needed by gtk_file_filter_get_attributes,
which directly returns the attributes that are needed.

Update all callers.
2020-07-05 15:10:13 -04:00
Matthias Clasen 644d522d19 filefilter: Drop custom filters
These don't work with native file choosers.
2020-07-05 14:34:33 -04:00
Matthias Clasen a8b0125da1 filefilter: Drop GtkFileFilterInfo
We can just make the filter operate on GFileInfo.
This is in preparation for making GtkFileFilter a
GtkFilter.

Update all users.
2020-07-05 13:55:42 -04:00
Matthias Clasen acccac516e filefiler: No more floating
Make GtkFileFilter not be initially unowned anymore.
This is in preparation for deriving GtkFileFilter
from GtkFilter. Update all callers.
2020-07-05 12:36:47 -04:00
Matthias Clasen d65214fa4e Merge branch 'wip/otte/for-master' into 'master'
Wip/otte/for master

See merge request GNOME/gtk!2193
2020-07-05 16:06:16 +00:00
Baurzhan Muftakhidinov 1d96fc8237 Update Kazakh translation 2020-07-05 12:51:00 +00:00
Florentina Mușat 882a87ca19 Update Romanian translation 2020-07-05 10:42:46 +00:00
Benjamin Otte 1dbb8df95f stringlist: Export gtk_string_object_new()
There are various use cases where it makes sense to construct these -
from our internal testing to using them in flatten- or mapmodels.
2020-07-05 02:59:21 +02:00
Benjamin Otte f6c2c2edbd stringlist: Call splice() for adding items after construction
This has the benefit of actually allowing NULL to be passed.
2020-07-05 02:59:21 +02:00
Benjamin Otte c4e4de36f6 stringlist: Remove n_additions argument from gtk_string_list_splice()
char ** arrays are null-terminated everywhere, so make sure they are in
splice(), too.

Also fix the argument to be a const char * const * like in the
constructor.
2020-07-05 02:59:21 +02:00
Benjamin Otte 67cbb2a7d3 stringlist: Clarify docs for gtk_string_list_get_string()
Make sure it's obvious that it behaves like g_list_model_get_item() and
returns NULL for pos >= n_items.
2020-07-05 02:59:21 +02:00
Benjamin Otte a979daa8ea stringlist: Make one constructor call the other
Simplifies code.
2020-07-05 02:59:21 +02:00
Benjamin Otte fb14f50ec1 stringlist: Make property not construct-only
Massively speeds up creation of long stringlists.
2020-07-05 02:59:21 +02:00
Benjamin Otte 6099fbafc1 bitset: Add gtk_bitset_new_range()
It's a common use.
2020-07-05 02:59:21 +02:00
Benjamin Otte 6f2f828bce tests: Make testlistview be a list again
The grid conversion was for testing and should never have been
committed.
2020-07-05 02:59:21 +02:00
Benjamin Otte 795d3122cc selectionmodels: Add set_model() support
Now that we don't care about item types anymore, we can make the child
models settable.

We try to retain the selection, even when the model changes.
2020-07-05 02:59:21 +02:00
Benjamin Otte 5080730728 listmodels: Stop respecting item-type
Simplify all view model APIs and always return G_TYPE_OBJECT as the
item-type for every model.

It turns out nobody uses item-type anyway.

So instead of adding lots of APIs, forcing people to think about it and
trying to figure out how to handle filter or map models that modify item
types, just having an easy life is a better approach.

All the models need to be able to deal with any type of object going
through anyway.
2020-07-05 02:59:21 +02:00
Benjamin Otte f75a3a0e95 stringlist: Take a const char const * argument
Sucks that we need to cast a char**, but otherwise we need to cast
{"foo", "bar", "baz" } arrays.
2020-07-05 02:34:42 +02:00
Benjamin Otte b75db7d1c6 stringfilter: Don't crash if the expression returns "" 2020-07-05 00:34:21 +02:00
Benjamin Otte b03069bdf6 a11y: Remove double initialization of variables 2020-07-05 00:34:21 +02:00
Yuri Chornoivan 1c71e56e75 Update Ukrainian translation 2020-07-04 17:02:55 +00:00
Matthias Clasen 9332d0dcc8 Merge branch 'typo' into 'master'
Fixes typos

See merge request GNOME/gtk!2188
2020-07-04 15:48:29 +00:00
Matthias Clasen 9ad37583e6 Merge branch 'matthiasc/for-master' into 'master'
filechooser: Make filtering work again

See merge request GNOME/gtk!2189
2020-07-04 15:46:19 +00:00
Matthias Clasen 69975627e9 filechooser: Make filtering work again
One too many lines were dropped when this filter combo
was converted to a dropdown. Bring it back, to make
filtering work again.
2020-07-04 10:28:10 -04:00
Piotr Drąg b74a489aba Update POTFILES.in and POTFILES.skip 2020-07-04 13:37:03 +02:00
Jordi Mas 599b807726 Fixes typos 2020-07-04 10:00:25 +02:00
Jordi Mas 6510ca8bdd Update Catalan translation 2020-07-04 09:58:03 +02:00
101 changed files with 7971 additions and 4676 deletions
+1 -1
View File
@@ -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);
+1
View File
@@ -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>
+63 -3
View 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);
+241
View File
@@ -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;
}
+1
View File
@@ -49,6 +49,7 @@ demos = files([
'listview_minesweeper.c',
'listview_settings.c',
'listview_weather.c',
'listview_words.c',
'markup.c',
'modelbutton.c',
'overlay.c',
+2 -2
View File
@@ -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" />
+12 -11
View File
@@ -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>
-1
View File
@@ -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;
+1 -1
View File
@@ -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;
+2
View File
@@ -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>
-137
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+8 -3
View File
@@ -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);
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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
View File
@@ -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);
}
/**
+9 -9
View File
@@ -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,
+2
View File
@@ -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;
+8 -50
View File
@@ -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;
+19 -10
View File
@@ -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);
}
+36 -14
View File
@@ -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);
+45 -18
View File
@@ -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
View File
@@ -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
View File
@@ -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
+3 -1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+13 -78
View File
@@ -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
+4 -56
View File
@@ -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
View File
@@ -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);
}
+8 -2
View File
@@ -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
+5 -41
View File
@@ -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;
+1 -2
View File
@@ -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,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1 -2
View File
@@ -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
View File
@@ -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]);
}
+3
View File
@@ -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
View File
@@ -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]);
}
+3
View File
@@ -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
+2 -2
View File
@@ -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
View File
@@ -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));
}
/*
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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,
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-2
View File
@@ -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
View File
@@ -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;
}
-70
View File
@@ -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,
+443
View File
@@ -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;
}
+57
View File
@@ -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__ */
+604
View File
@@ -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;
}
+57
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-3
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+283
View File
@@ -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
+2 -2
View File
@@ -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);
+7 -7
View File
@@ -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);
}
+4
View File
@@ -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',
+1
View File
@@ -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
+2 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+416 -394
View File
File diff suppressed because it is too large Load Diff
+338 -339
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -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
+1
View File
@@ -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
+415 -440
View File
File diff suppressed because it is too large Load Diff
+210 -222
View File
File diff suppressed because it is too large Load Diff
+4 -18
View File
@@ -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
View File
@@ -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 ();
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+1 -1
View File
@@ -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);
+479
View File
@@ -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 ();
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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);
+3
View File
@@ -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'],
]
+54
View File
@@ -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 ();
}
+52
View File
@@ -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 ();
}
+1 -5
View File
@@ -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);
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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");
+443
View File
@@ -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 ();
}
+105
View File
@@ -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