Compare commits
149 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d233b10559 | |||
| b4f9f252d7 | |||
| 373c06b148 | |||
| c84cd97fbc | |||
| 6b7d295cfe | |||
| 481d438380 | |||
| f4e1057431 | |||
| fa0166180e | |||
| 13d84c202b | |||
| 5846794075 | |||
| 201da90e23 | |||
| 8d4fcabf01 | |||
| 3f8735a488 | |||
| a4dc248512 | |||
| ef451b056a | |||
| 59aaabb161 | |||
| 663ca21328 | |||
| 77435d31fa | |||
| 6edb8f096f | |||
| c4dfee8860 | |||
| 8ac1e77c9a | |||
| 65ceb6c15a | |||
| f70d10f6ac | |||
| 0bbd083d79 | |||
| 102d2986c6 | |||
| c74201ca87 | |||
| b09019a5b4 | |||
| 1dd08ad8db | |||
| eb0704855f | |||
| c4c1d4a1b3 | |||
| e6756f605e | |||
| 1f4b8e089e | |||
| c0e08db739 | |||
| 1c337d350d | |||
| 81e675dfbf | |||
| 8556221429 | |||
| 1b4109a7fd | |||
| df0786be7a | |||
| 3f545da08d | |||
| 7170fdebb9 | |||
| 7ccf32db57 | |||
| 520c2116a3 | |||
| e818685921 | |||
| 6ddd9793f3 | |||
| 6bdca276a2 | |||
| d4ff275002 | |||
| 2b6f243578 | |||
| 8770584bfb | |||
| 4f7f15700c | |||
| cab6808673 | |||
| b77110c35a | |||
| c4e8218f49 | |||
| c8b57154cb | |||
| c4b2112f16 | |||
| 3132353ec5 | |||
| 3dc6267146 | |||
| 6a6146a9e0 | |||
| 01fbf8444b | |||
| 1f8c79eca1 | |||
| 5229069101 | |||
| a6752bd3e0 | |||
| 93a51f77c4 | |||
| 9f2926dde3 | |||
| d31bb8b503 | |||
| d46b04631e | |||
| 30eca5a523 | |||
| 4fa71fd82a | |||
| 6819c7c792 | |||
| 0c9a0dfed1 | |||
| 5d9bcfb64a | |||
| 7047d68404 | |||
| 334f95479b | |||
| 9dff4d6ff3 | |||
| 4d7d031ee0 | |||
| 7c98af6358 | |||
| ddcba4d33f | |||
| 59fe4a3a09 | |||
| 6774f36636 | |||
| 608cbc28af | |||
| 117c71faeb | |||
| 24d6a190af | |||
| 6a4b5ead86 | |||
| 674ede8665 | |||
| 8a269de89a | |||
| ace4eac25a | |||
| 66bce08d10 | |||
| 65902367c6 | |||
| 8f0b92e42d | |||
| f3d5f6628d | |||
| 4d687366ed | |||
| 3aa5019e70 | |||
| 4fb495d0fe | |||
| c447fa8442 | |||
| 3a70ca9d03 | |||
| 5d11e9812d | |||
| 0d10982379 | |||
| c20a966f06 | |||
| 64db05d3dd | |||
| 913cd91df0 | |||
| 2c5533589d | |||
| cfdc81af02 | |||
| 7fa8a69fdc | |||
| fd2861d683 | |||
| cd9f5733b3 | |||
| 8b4560cbfb | |||
| 2d914d52be | |||
| a26865e741 | |||
| 3558beaa61 | |||
| 9b9a9f14e2 | |||
| 0ce4f66976 | |||
| b81bbde7c8 | |||
| 3f55bfe2cb | |||
| 4185ba242b | |||
| e04191a5ea | |||
| f07d304f19 | |||
| 1d1f618a13 | |||
| e20610cdc6 | |||
| 721396b6d6 | |||
| dc1dbe6158 | |||
| 30488e60e2 | |||
| a5949960bc | |||
| ec4a489093 | |||
| 7c52e03815 | |||
| 724c9361f3 | |||
| 147388e69a | |||
| 64aa281c97 | |||
| c2b0330c56 | |||
| de4803bb21 | |||
| e574dcb091 | |||
| 488b0cbb69 | |||
| 6ceab55148 | |||
| 3d8b6f6b79 | |||
| 58d3213eef | |||
| 006dfdc55a | |||
| a38c423ddb | |||
| fa0295629b | |||
| 8395698090 | |||
| 277a91dbf8 | |||
| ff36cfb5be | |||
| db452f0c45 | |||
| 5b1195f874 | |||
| d830724d4f | |||
| 0ef0edfa9a | |||
| 0ec868bd69 | |||
| 30e79e8412 | |||
| c9b032acab | |||
| 1f410faccb | |||
| d0e56106fe | |||
| 3d3d7dbc59 |
@@ -4,8 +4,15 @@ set -e
|
||||
|
||||
# We need to add a new remote for the upstream master, since this script could
|
||||
# be running in a personal fork of the repository which has out of date branches.
|
||||
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
|
||||
git fetch upstream
|
||||
if [ "${CI_PROJECT_NAMESPACE}" != "GNOME" ]; then
|
||||
echo "Retrieving the current upstream repository from ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}..."
|
||||
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
|
||||
git fetch upstream
|
||||
ORIGIN="upstream"
|
||||
else
|
||||
echo "Reusing the existing repository on ${CI_PROJECT_NAMESPACE}/${CI_PROJECT_NAME}"
|
||||
ORIGIN="origin"
|
||||
fi
|
||||
|
||||
# Work out the newest common ancestor between the detached HEAD that this CI job
|
||||
# has checked out, and the upstream target branch (which will typically be
|
||||
@@ -13,7 +20,7 @@ git fetch upstream
|
||||
#
|
||||
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` is only defined if we’re running in
|
||||
# a merge request pipeline; fall back to `${CI_DEFAULT_BRANCH}` otherwise.
|
||||
newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "upstream/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent HEAD) | head -1)
|
||||
newest_common_ancestor_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "${ORIGIN}/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}") <(git rev-list --first-parent HEAD) | head -1)
|
||||
git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format" -p1
|
||||
exit_status=$?
|
||||
|
||||
|
||||
@@ -225,6 +225,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>
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* Creates a list model containing the completions */
|
||||
static GListModel *
|
||||
/* Creates a tree model containing the completions */
|
||||
static GtkTreeModel *
|
||||
create_completion_model (void)
|
||||
{
|
||||
const char *strings[] = {
|
||||
@@ -42,8 +42,20 @@ create_completion_model (void)
|
||||
"aæz",
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
GtkListStore *store;
|
||||
GtkTreeIter iter;
|
||||
|
||||
return G_LIST_MODEL (gtk_string_list_new (strings));
|
||||
store = gtk_list_store_new (1, G_TYPE_STRING);
|
||||
|
||||
for (i = 0; strings[i]; i++)
|
||||
{
|
||||
/* Append one word */
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter, 0, strings[i], -1);
|
||||
}
|
||||
|
||||
return GTK_TREE_MODEL (store);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +67,7 @@ do_entry_completion (GtkWidget *do_widget)
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
GtkEntryCompletion *completion;
|
||||
GListModel *completion_model;
|
||||
GtkTreeModel *completion_model;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
@@ -93,6 +105,9 @@ do_entry_completion (GtkWidget *do_widget)
|
||||
gtk_entry_completion_set_model (completion, completion_model);
|
||||
g_object_unref (completion_model);
|
||||
|
||||
/* Use model column 0 as the text column */
|
||||
gtk_entry_completion_set_text_column (completion, 0);
|
||||
|
||||
gtk_entry_completion_set_inline_completion (completion, TRUE);
|
||||
gtk_entry_completion_set_inline_selection (completion, TRUE);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
* The dataset used here has up to 16 777 216 items.
|
||||
*
|
||||
* Note that this demo also functions as a performance
|
||||
* test for some of the list model machinery, and biggest
|
||||
* sizes here can lock up the application for extended
|
||||
* times when used with sorting.
|
||||
* test for some of the list model machinery, and the
|
||||
* biggest sizes here can lock up the application for
|
||||
* extended times when used with sorting.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
@@ -30,7 +30,6 @@ struct _GtkColor
|
||||
char *name;
|
||||
GdkRGBA color;
|
||||
int h, s, v;
|
||||
gboolean selected;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -43,7 +42,6 @@ enum {
|
||||
PROP_HUE,
|
||||
PROP_SATURATION,
|
||||
PROP_VALUE,
|
||||
PROP_SELECTED,
|
||||
|
||||
N_COLOR_PROPS
|
||||
};
|
||||
@@ -206,10 +204,6 @@ gtk_color_get_property (GObject *object,
|
||||
g_value_set_int (value, self->v);
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
g_value_set_boolean (value, self->selected);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -239,10 +233,6 @@ gtk_color_set_property (GObject *object,
|
||||
self->v = round (100 * v);
|
||||
break;
|
||||
|
||||
case PROP_SELECTED:
|
||||
self->selected = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -284,8 +274,6 @@ gtk_color_class_init (GtkColorClass *klass)
|
||||
g_param_spec_int ("saturation", NULL, NULL, 0, 100, 0, G_PARAM_READABLE);
|
||||
color_properties[PROP_VALUE] =
|
||||
g_param_spec_int ("value", NULL, NULL, 0, 100, 0, G_PARAM_READABLE);
|
||||
color_properties[PROP_SELECTED] =
|
||||
g_param_spec_boolean ("selected", NULL, NULL, FALSE, G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_COLOR_PROPS, color_properties);
|
||||
}
|
||||
@@ -673,7 +661,7 @@ create_color_grid (void)
|
||||
|
||||
model = G_LIST_MODEL (gtk_sort_list_model_new (gtk_color_list_new (0), NULL));
|
||||
|
||||
selection = G_LIST_MODEL (gtk_property_selection_new (model, "selected"));
|
||||
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
|
||||
g_object_unref (selection);
|
||||
g_object_unref (model);
|
||||
@@ -727,16 +715,17 @@ limit_changed_cb2 (GtkDropDown *dropdown,
|
||||
GParamSpec *pspec,
|
||||
GtkLabel *label)
|
||||
{
|
||||
gpointer item;
|
||||
char *string;
|
||||
int len;
|
||||
guint limit;
|
||||
|
||||
item = gtk_drop_down_get_selected_item (dropdown);
|
||||
g_object_get (item, "string", &string, NULL);
|
||||
limit = 1 << (3 * (gtk_drop_down_get_selected (dropdown) + 1));
|
||||
|
||||
string = g_strdup_printf ("%'u", limit);
|
||||
len = g_utf8_strlen (string, -1);
|
||||
g_free (string);
|
||||
|
||||
gtk_label_set_max_width_chars (label, len + 2); /* for " /" */
|
||||
gtk_label_set_width_chars (label, len + 2); /* for " /" */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -749,11 +738,44 @@ items_changed_cb (GListModel *model,
|
||||
guint n = g_list_model_get_n_items (model);
|
||||
char *text;
|
||||
|
||||
text = g_strdup_printf ("%u /", n);
|
||||
text = g_strdup_printf ("%'u /", n);
|
||||
gtk_label_set_label (GTK_LABEL (label), text);
|
||||
g_free (text);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_number_item (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
PangoAttrList *attrs;
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1);
|
||||
|
||||
attrs = pango_attr_list_new ();
|
||||
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum"));
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
|
||||
gtk_list_item_set_child (item, label);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_number_item (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
guint limit;
|
||||
char *string;
|
||||
|
||||
label = gtk_list_item_get_child (item);
|
||||
|
||||
limit = 1 << (3 * (gtk_list_item_get_position (item) + 1));
|
||||
string = g_strdup_printf ("%'u", limit);
|
||||
gtk_label_set_label (GTK_LABEL (label), string);
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
@@ -773,6 +795,8 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
GtkWidget *button;
|
||||
GtkWidget *label;
|
||||
PangoAttrList *attrs;
|
||||
char *string;
|
||||
guint len;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
||||
@@ -805,8 +829,12 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
pango_attr_list_insert (attrs, pango_attr_font_features_new ("tnum"));
|
||||
gtk_label_set_attributes (GTK_LABEL (label), attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
gtk_label_set_width_chars (GTK_LABEL (label), 6);
|
||||
string = g_strdup_printf ("%'u", 4096);
|
||||
len = g_utf8_strlen (string, -1);
|
||||
g_free (string);
|
||||
gtk_label_set_width_chars (GTK_LABEL (label), len + 2);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 1);
|
||||
|
||||
g_signal_connect (gtk_grid_view_get_model (GTK_GRID_VIEW (gridview)),
|
||||
"items-changed", G_CALLBACK (items_changed_cb), label);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), label);
|
||||
@@ -819,6 +847,11 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
g_signal_connect (dropdown, "notify::selected",
|
||||
G_CALLBACK (limit_changed_cb2),
|
||||
label);
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_number_item), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_number_item), NULL);
|
||||
gtk_drop_down_set_factory (GTK_DROP_DOWN (dropdown), factory);
|
||||
g_object_unref (factory);
|
||||
gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), 3); /* 4096 */
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), dropdown);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
+2
-12
@@ -133,7 +133,7 @@ gtk_demo_run (GtkDemo *self,
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
activate_about (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
@@ -1155,7 +1155,7 @@ out:
|
||||
static void
|
||||
print_version (void)
|
||||
{
|
||||
g_print ("gtk3-demo %d.%d.%d\n",
|
||||
g_print ("gtk4-demo %d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
@@ -1197,16 +1197,6 @@ main (int argc, char **argv)
|
||||
};
|
||||
int i;
|
||||
|
||||
/* Most code in gtk-demo is intended to be exemplary, but not
|
||||
* these few lines, which are just a hack so gtk-demo will work
|
||||
* in the GTK tree without installing it.
|
||||
*/
|
||||
if (g_file_test ("../../modules/input/immodules.cache", G_FILE_TEST_EXISTS))
|
||||
{
|
||||
g_setenv ("GTK_IM_MODULE_FILE", "../../modules/input/immodules.cache", TRUE);
|
||||
}
|
||||
/* -- End of hack -- */
|
||||
|
||||
app = gtk_application_new ("org.gtk.Demo4", G_APPLICATION_NON_UNIQUE|G_APPLICATION_HANDLES_COMMAND_LINE);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
|
||||
@@ -16,15 +16,6 @@
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
<object class="GtkTreeStore" id="treestore">
|
||||
<columns>
|
||||
<column type="gchararray"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gpointer"/>
|
||||
<column type="gint"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkApplicationWindow" id="window">
|
||||
<style>
|
||||
<class name="devel"/>
|
||||
|
||||
@@ -49,6 +49,7 @@ demos = files([
|
||||
'listview_minesweeper.c',
|
||||
'listview_settings.c',
|
||||
'listview_weather.c',
|
||||
'listview_words.c',
|
||||
'markup.c',
|
||||
'modelbutton.c',
|
||||
'overlay.c',
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
259|GTK+ and friends|GTKtoolkit|#java bindings version 4.0.16 released: http://article.gmane.org/gmane.comp.gnome.bindings.java/1796 #gtk|1276885917|0||0|0
|
||||
260|GTK+ and friends|GTKtoolkit|RT @cwiiis: MxIconTheme and MxIcon respect system's icon theme (and changes) now in #mx master :) Made possible by @thosw's XSettings work|1276883019|0||0|0
|
||||
261|GTK+ and friends|GTKtoolkit|#javascript mailing list just created. Discuss its usage in GObject libraries: GTK+, Glib ... http://ur1.ca/08lwz by @jwendell #gtk|1276842639|0||0|0
|
||||
262|GTK+ and friends|GTKtoolkit|Note fot Win32 users: XP theming is back in 2.90.3 . Please test. #gtk|1276829697|0||0|0
|
||||
262|GTK+ and friends|GTKtoolkit|Note for Win32 users: XP theming is back in 2.90.3 . Please test. #gtk|1276829697|0||0|0
|
||||
263|GTK+ and friends|GTKtoolkit|GTK+ 2.90.3 (unstable) released: http://mail.gnome.org/archives/gtk-devel-list/2010-June/msg00137.html #gtk|1276829633|0||0|0
|
||||
264|GTK+ and friends|GTKtoolkit|GLib 2.25.9 (unstable) released: http://ur1.ca/08hrl WARNING: API changes in GDBus, GSettings and GApplication #gtk|1276829581|0||0|0
|
||||
265|scaroo|scaroo|RT @scaroo: #SeedKit does RGBA window with css shadows and stuff : http://dl.dropbox.com/u/5746554/seedkit-does-rgba.png|1276734086|0|GTKtoolkit|0|1
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window">
|
||||
<style>
|
||||
<class name="devel"/>
|
||||
</style>
|
||||
<property name="title" translatable="yes">Help</property>
|
||||
<property name="default-width">720</property>
|
||||
<property name="default-height">520</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<child>
|
||||
<object class="GtkTextView" id="text_view">
|
||||
<property name="wrap-mode">word</property>
|
||||
<property name="left-margin">20</property>
|
||||
<property name="right-margin">20</property>
|
||||
<property name="top-margin">20</property>
|
||||
<property name="bottom-margin">20</property>
|
||||
<property name="buffer">
|
||||
<object class="GtkTextBuffer" id="buffer"/>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -51,21 +51,121 @@ node_editor_application_init (NodeEditorApplication *app)
|
||||
}
|
||||
|
||||
static void
|
||||
quit_activated (GSimpleAction *action,
|
||||
activate_about (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer data)
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkApplication *app = user_data;
|
||||
char *version;
|
||||
GString *s;
|
||||
GskRenderer *gsk_renderer;
|
||||
const char *renderer;
|
||||
|
||||
s = g_string_new ("");
|
||||
|
||||
g_string_append (s, "System libraries\n");
|
||||
g_string_append_printf (s, "\tGLib\t%d.%d.%d\n",
|
||||
glib_major_version,
|
||||
glib_minor_version,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (s, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (s, "\tGTK\t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
gsk_renderer = gtk_native_get_renderer (GTK_NATIVE (gtk_application_get_active_window (app)));
|
||||
if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskVulkanRenderer") == 0)
|
||||
renderer = "Vulkan";
|
||||
else if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskGLRenderer") == 0)
|
||||
renderer = "OpenGL";
|
||||
else if (strcmp (G_OBJECT_TYPE_NAME (gsk_renderer), "GskCairoRenderer") == 0)
|
||||
renderer = "Cairo";
|
||||
else
|
||||
renderer = "Unknown";
|
||||
|
||||
g_string_append_printf (s, "\nRenderer\n\t%s", renderer);
|
||||
|
||||
version = g_strdup_printf ("%s\nRunning against GTK %d.%d.%d",
|
||||
PACKAGE_VERSION,
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
gtk_show_about_dialog (GTK_WINDOW (gtk_application_get_active_window (app)),
|
||||
"program-name", "GTK Node Editor",
|
||||
"version", version,
|
||||
"copyright", "© 2019—2020 The GTK Team",
|
||||
"license-type", GTK_LICENSE_LGPL_2_1,
|
||||
"website", "http://www.gtk.org",
|
||||
"comments", "Program to test GTK rendering",
|
||||
"authors", (const char *[]){ "Benjamin Otte", "Timm Bäder", NULL},
|
||||
"logo-icon-name", "text-editor-symbolic",
|
||||
"title", "About GTK Node Editor",
|
||||
"system-information", s->str,
|
||||
NULL);
|
||||
|
||||
g_string_free (s, TRUE);
|
||||
g_free (version);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_quit (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer data)
|
||||
{
|
||||
g_application_quit (G_APPLICATION (data));
|
||||
}
|
||||
|
||||
static void
|
||||
activate_inspector (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_window_set_interactive_debugging (TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_help (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *window;
|
||||
GtkTextBuffer *buffer;
|
||||
GBytes *bytes;
|
||||
const char *text;
|
||||
gsize len;
|
||||
|
||||
builder = gtk_builder_new ();
|
||||
gtk_builder_add_from_resource (builder, "/org/gtk/gtk4/node-editor/help-window.ui", NULL);
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
|
||||
buffer = GTK_TEXT_BUFFER (gtk_builder_get_object (builder, "buffer"));
|
||||
|
||||
bytes = g_resources_lookup_data ("/org/gtk/gtk4/node-editor/node-format.md",
|
||||
G_RESOURCE_LOOKUP_FLAGS_NONE,
|
||||
NULL);
|
||||
text = g_bytes_get_data (bytes, &len);
|
||||
gtk_text_buffer_set_text (buffer, text, len);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
g_object_unref (builder);
|
||||
}
|
||||
|
||||
static GActionEntry app_entries[] =
|
||||
{
|
||||
{ "quit", quit_activated, NULL, NULL, NULL }
|
||||
{ "about", activate_about, NULL, NULL, NULL },
|
||||
{ "quit", activate_quit, NULL, NULL, NULL },
|
||||
{ "inspector", activate_inspector, NULL, NULL, NULL },
|
||||
{ "help", activate_help, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
static void
|
||||
node_editor_application_startup (GApplication *app)
|
||||
{
|
||||
const char *help_accels[2] = { "F1", NULL };
|
||||
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
|
||||
const char *open_accels[2] = { "<Ctrl>O", NULL };
|
||||
GtkCssProvider *provider;
|
||||
@@ -75,6 +175,7 @@ node_editor_application_startup (GApplication *app)
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
app);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.help", help_accels);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels);
|
||||
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
|
||||
|
||||
|
||||
@@ -825,6 +825,7 @@ node_editor_window_create_renderer_widget (gpointer item,
|
||||
gtk_widget_set_size_request (box, 120, 90);
|
||||
|
||||
label = gtk_label_new (g_object_get_data (G_OBJECT (paintable), "description"));
|
||||
gtk_widget_add_css_class (label, "title-4");
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
picture = gtk_picture_new_for_paintable (paintable);
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="gear_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Help</attribute>
|
||||
<attribute name="action">app.help</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Inspector</attribute>
|
||||
<attribute name="action">app.inspector</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_About Node Editor</attribute>
|
||||
<attribute name="action">app.about</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
|
||||
<object class="GtkPopover" id="testcase_popover">
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
@@ -119,6 +136,13 @@
|
||||
<property name="popover">testcase_popover</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkMenuButton" id="gear_menu_button">
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">gear_menu</property>
|
||||
<property name="icon-name">open-menu-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
<gresources>
|
||||
<gresource prefix="/org/gtk/gtk4/node-editor">
|
||||
<file preprocess="xml-stripblanks">node-editor-window.ui</file>
|
||||
<file preprocess="xml-stripblanks">help-window.ui</file>
|
||||
<file>node-format.md</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
# The Node file format
|
||||
|
||||
GSK render nodes can be serialized and deserialized using APIs such as `gsk_render_node_serialize()` and `gsk_render_node_deserialize()`. The intended use for this is development - primarily the development of GTK - by allowing things such as creating testsuites and benchmarks, exchanging nodes in bug reports. GTK includes the `gtk4-node-editor` application for creating such test files.
|
||||
|
||||
The format is a text format that follows the [CSS syntax rules](https://drafts.csswg.org/css-syntax-3/). In particular, this means that every array of bytes will produce a render node when parsed, as there is a defined error recovery method. For more details on error handling, please refer to the documentation of the aprsing APIs.
|
||||
|
||||
The grammar of a node text representation using [the CSS value definition syntax](https://drafts.csswg.org/css-values-3/#value-defs) looks like this:
|
||||
**document**: `<node>\*`
|
||||
**node**: container { <document> } | `<node-name> { <property>* }`
|
||||
**property**: `<property-name>: <node> | <value> ;`
|
||||
|
||||
Each node has its own `<node-name>` and supports a custom set of properties, each with their own `<property-name>` and syntax. The following paragraphs document each of the nodes and their properties.
|
||||
|
||||
When serializing and the value of a property equals the default value, this value will not be serialized. Serialization aims to produce an output as small as possible.
|
||||
|
||||
# Nodes
|
||||
|
||||
### container
|
||||
|
||||
The **container** node is a special node that allows specifying a list of child nodes. Its contents follow the same rules as an empty document.
|
||||
|
||||
### blend
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| bottom | `<node>` | color { color: #AF0; } | always |
|
||||
| mode | `<blend-mode>` | normal | non-default |
|
||||
| top | `<node>` | color { } | always |
|
||||
|
||||
Creates a node like `gsk_blend_node_new()` with the given properties.
|
||||
|
||||
### blur
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| blur | `<number>` | 1 | non-default |
|
||||
| child | `<node>` | color { } | always |
|
||||
|
||||
Creates a node like `gsk_blur_node_new()` with the given properties.
|
||||
|
||||
### border
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| color | `<color>{1,4}` | black | non-default |
|
||||
| outline | `<rounded-rect>` | 50 | always |
|
||||
| width | `<number>{1,4}` | 1 | non-default |
|
||||
|
||||
Creates a node like `gsk_border_node_new()` with the given properties.
|
||||
|
||||
For the color and width properties, the values follow the typical CSS order of top, right, bottom, left. If the last/left value isn't given, the 2nd/right value is used. If the 3rd/bottom value isn't given, the 1st/top value is used. And if the 2nd/right value also isn't given, the 1st/top value is used for every 4 values.
|
||||
|
||||
### clip
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| clip | `<rounded-rect>` | 50 | always |
|
||||
|
||||
Creates a node like `gsk_clip_node_new()` with the given properties.
|
||||
|
||||
As an extension, this node allows specifying a rounded rectangle for the clip property. If that rectangle is indeed rounded, a node like `gsk_rounded_clip_node_new()` will be created instead.
|
||||
|
||||
### color
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| bounds | `<rect>` | 50 | always |
|
||||
| color | `<color>` | #FF00CC | always |
|
||||
|
||||
Creates a node like `gsk_color_node_new()` with the given properties.
|
||||
|
||||
The color is chosen as an error pink so it is visible while also reminding people to change it.
|
||||
|
||||
### color-matrix
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| matrix | `<transform>` | none | non-default |
|
||||
| offset | `<number>{4}` | 0 0 0 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_color_matrix_node_new()` with the given properties.
|
||||
|
||||
The matrix property accepts a <transform> for compatibility purposes, but you should be aware that the allowed values are meant to be used on 3D transformations, so their naming might appear awkward. However, it is always possible to use the matrix3d() production to specify all 16 values individually.
|
||||
|
||||
### cross-fade
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| end | `<node>` | color { } | always |
|
||||
| mode | `<number>` | 0.5 | non-default |
|
||||
| start | `<node>` | color { color: #AF0; } | always |
|
||||
|
||||
Creates a node like `gsk_cross_fade_node_new()` with the given properties.
|
||||
|
||||
### debug
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| message | `<string>` | "" | non-default |
|
||||
|
||||
Creates a node like `gsk_debug_node_new()` with the given properties.
|
||||
|
||||
### inset-shadow
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| blur | `<number>` | 0 | non-default |
|
||||
| color | `<color>` | black | non-default |
|
||||
| dx | `<number>` | 1 | non-default |
|
||||
| dy | `<number>` | 1 | non-default |
|
||||
| outline | `<rounded-rect>` | 50 | always |
|
||||
| spread | `<number>` | 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_inset_shadow_node_new()` with the given properties.
|
||||
|
||||
### linear-gradient
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| bounds | `<rect>` | 50 | always |
|
||||
| end | `<point>` | 0 50 | always |
|
||||
| start | `<point>` | 0 0 | always |
|
||||
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
|
||||
|
||||
Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
|
||||
|
||||
### opacity
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| opacity | `<number>` | 0.5 | non-default |
|
||||
|
||||
Creates a node like `gsk_transform_node_new()` with the given properties.
|
||||
|
||||
### outset-shadow
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| blur | `<number>` | 0 | non-default |
|
||||
| color | `<color>` | black | non-default |
|
||||
| dx | `<number>` | 1 | non-default |
|
||||
| dy | `<number>` | 1 | non-default |
|
||||
| outline | `<rounded-rect>` | 50 | always |
|
||||
| spread | `<number>` | 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_outset_shadow_node_new()` with the given properties.
|
||||
|
||||
### repeat
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| bounds | `<rect>` | *bounds of child node* | non-default |
|
||||
| child | `<node>` | color { } | always |
|
||||
| child-bounds| `<rect>` | *bounds of child node* | non-default |
|
||||
|
||||
Creates a node like `gsk_repeat_node_new()` with the given properties.
|
||||
|
||||
### rounded-clip
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| clip | `<rounded-rect>` | 50 | always |
|
||||
|
||||
Creates a node like `gsk_rounded_clip_node_new()` with the given properties.
|
||||
|
||||
### shadow
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| shadow | `<shadow>` | black 1 1 | always |
|
||||
|
||||
Creates a node like `gsk_shadow_node_new()` with the given properties.
|
||||
|
||||
### text
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| color | `<color>` | black | non-default |
|
||||
| font | `<string>` | "Cantarell 11" | always |
|
||||
| glyphs | `<glyphs>` | "Hello" | always |
|
||||
| offset | `<point>` | 0 0 | non-default |
|
||||
|
||||
Creates a node like `gsk_text_node_new()` with the given properties.
|
||||
|
||||
If the given font does not exist or the given glyphs are invalid for the given font, an error node will be returned.
|
||||
|
||||
### texture
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| bounds | `<rect>` | 50 | always |
|
||||
| texture | `<url>` | *see below* | always |
|
||||
|
||||
Creates a node like `gsk_texture_node_new()` with the given properties.
|
||||
|
||||
The default texture is a 10x10 checkerboard with the top left and bottom right 5x5 being in the color #FF00CC and the other part being transparent. A possible representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQXY0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=")
|
||||
`.
|
||||
|
||||
### transform
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| -------- | ---------------- | ---------------------- | ----------- |
|
||||
| child | `<node>` | color { } | always |
|
||||
| transform| `<transform>` | none | non-default |
|
||||
|
||||
Creates a node like `gsk_transform_node_new()` with the given properties.
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
executable('print-editor',
|
||||
executable('gtk4-print-editor',
|
||||
['print-editor.c'],
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_dep,
|
||||
include_directories: confinc,
|
||||
gui_app: true,
|
||||
link_args: extra_demo_ldflags)
|
||||
link_args: extra_demo_ldflags,
|
||||
install: true)
|
||||
|
||||
# desktop file
|
||||
install_data('org.gtk.PrintEditor4.desktop', install_dir: gtk_applicationsdir)
|
||||
|
||||
# appdata
|
||||
install_data('org.gtk.PrintEditor4.appdata.xml', install_dir: gtk_appdatadir)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>org.gtk.PrintEditor4.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>LGPL-2.0+</project_license>
|
||||
<name>GTK Print Editor</name>
|
||||
<summary>Program to demonstrate GTK printing</summary>
|
||||
<description>
|
||||
<p>
|
||||
GTK Print Editor is a simple editor to demonstrate GTK printing.
|
||||
</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot>
|
||||
<image>https://static.gnome.org/appdata/gtk4-print-editor/gtk-print-editor1.png</image>
|
||||
<caption>Print Editor</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<kudos>
|
||||
<kudo>HiDpiIcon</kudo>
|
||||
<kudo>ModernToolkit</kudo>
|
||||
</kudos>
|
||||
<url type="homepage">https://www.gtk.org</url>
|
||||
<translation type="gettext">gtk-4.0</translation>
|
||||
<update_contact>matthias.clasen_at_gmail.com</update_contact>
|
||||
<developer_name>Matthias Clasen and others</developer_name>
|
||||
<releases>
|
||||
<release version="3.99.0" date="2020">
|
||||
<description>
|
||||
<p>A new developers snapshot towards GTK 4.0.</p>
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
@@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Name=Print Editor
|
||||
Comment=A simple editor demonstrating GTK printing
|
||||
Exec=gtk4-print-editor %f
|
||||
Icon=text-editor-symbolic
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=Development;GTK;
|
||||
NoDisplay=true
|
||||
@@ -23,7 +23,7 @@ update_title (GtkWindow *window)
|
||||
else
|
||||
basename = g_file_get_basename (filename);
|
||||
|
||||
title = g_strdup_printf ("Simple Editor with printing - %s", basename);
|
||||
title = g_strdup_printf ("GTK Print Editor — %s", basename);
|
||||
g_free (basename);
|
||||
|
||||
gtk_window_set_title (window, title);
|
||||
@@ -592,18 +592,54 @@ activate_about (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *authors[] = {
|
||||
"Alexander Larsson",
|
||||
NULL
|
||||
};
|
||||
char *version;
|
||||
GString *sysinfo;
|
||||
char *setting;
|
||||
char **backends;
|
||||
int i;
|
||||
|
||||
sysinfo = g_string_new ("System libraries\n");
|
||||
g_string_append_printf (sysinfo, "\tGLib\t%d.%d.%d\n",
|
||||
glib_major_version,
|
||||
glib_minor_version,
|
||||
glib_micro_version);
|
||||
g_string_append_printf (sysinfo, "\tPango\t%s\n",
|
||||
pango_version_string ());
|
||||
g_string_append_printf (sysinfo, "\tGTK\t%d.%d.%d\n",
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
g_string_append (sysinfo, "\nPrint backends\n");
|
||||
|
||||
g_object_get (gtk_settings_get_default (), "gtk-print-backends", &setting, NULL);
|
||||
backends = g_strsplit (setting, ",", -1);
|
||||
for (i = 0; backends[i]; i++)
|
||||
g_string_append_printf (sysinfo, "\t%s\n", backends[i]);
|
||||
g_strfreev (backends);
|
||||
g_free (setting);
|
||||
|
||||
version = g_strdup_printf ("%s\nRunning against GTK %d.%d.%d",
|
||||
PACKAGE_VERSION,
|
||||
gtk_get_major_version (),
|
||||
gtk_get_minor_version (),
|
||||
gtk_get_micro_version ());
|
||||
|
||||
gtk_show_about_dialog (GTK_WINDOW (main_window),
|
||||
"name", "Print Test Editor",
|
||||
"logo-icon-name", "text-editor-symbolic",
|
||||
"version", PACKAGE_VERSION,
|
||||
"program-name", "GTK Print Editor",
|
||||
"version", version,
|
||||
"copyright", "© 2006-2020 Red Hat, Inc",
|
||||
"comments", "Program to demonstrate GTK printing.",
|
||||
"authors", authors,
|
||||
"license-type", GTK_LICENSE_LGPL_2_1,
|
||||
"website", "http://www.gtk.org",
|
||||
"comments", "Program to demonstrate GTK printing",
|
||||
"authors", (const char *[]){ "Alexander Larsson", NULL },
|
||||
"logo-icon-name", "text-editor-symbolic",
|
||||
"title", "About GTK Print Editor",
|
||||
"system-information", sysinfo->str,
|
||||
NULL);
|
||||
|
||||
g_string_free (sysinfo, TRUE);
|
||||
g_free (version);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -643,23 +679,6 @@ static const gchar ui_info[] =
|
||||
"<interface>"
|
||||
" <menu id='menubar'>"
|
||||
" <submenu>"
|
||||
" <attribute name='label'>_Application</attribute>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_About</attribute>"
|
||||
" <attribute name='action'>app.about</attribute>"
|
||||
" <attribute name='accel'><Primary>a</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Quit</attribute>"
|
||||
" <attribute name='action'>app.quit</attribute>"
|
||||
" <attribute name='accel'><Primary>q</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" </submenu>"
|
||||
" <submenu>"
|
||||
" <attribute name='label'>_File</attribute>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
@@ -696,6 +715,23 @@ static const gchar ui_info[] =
|
||||
" <attribute name='action'>app.print</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_Quit</attribute>"
|
||||
" <attribute name='action'>app.quit</attribute>"
|
||||
" <attribute name='accel'><Primary>q</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" </submenu>"
|
||||
" <submenu>"
|
||||
" <attribute name='label'>_Help</attribute>"
|
||||
" <section>"
|
||||
" <item>"
|
||||
" <attribute name='label'>_About Print Editor</attribute>"
|
||||
" <attribute name='action'>app.about</attribute>"
|
||||
" <attribute name='accel'><Primary>a</attribute>"
|
||||
" </item>"
|
||||
" </section>"
|
||||
" </submenu>"
|
||||
" </menu>"
|
||||
"</interface>";
|
||||
@@ -716,25 +752,6 @@ mark_set_callback (GtkTextBuffer *text_buffer,
|
||||
update_statusbar ();
|
||||
}
|
||||
|
||||
static gint
|
||||
command_line (GApplication *application,
|
||||
GApplicationCommandLine *command_line)
|
||||
{
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
argv = g_application_command_line_get_arguments (command_line, &argc);
|
||||
|
||||
if (argc == 2)
|
||||
{
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[1]);
|
||||
load_file (file);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
startup (GApplication *app)
|
||||
{
|
||||
@@ -809,6 +826,20 @@ activate (GApplication *app)
|
||||
gtk_widget_show (main_window);
|
||||
}
|
||||
|
||||
static void
|
||||
open (GApplication *application,
|
||||
GFile **files,
|
||||
int n_files,
|
||||
const char *hint)
|
||||
{
|
||||
if (n_files > 1)
|
||||
g_warning ("Can only open a single file");
|
||||
|
||||
activate (application);
|
||||
|
||||
load_file (files[0]);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -832,7 +863,7 @@ main (int argc, char **argv)
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
app = gtk_application_new ("org.gtk.PrintEditor", 0);
|
||||
app = gtk_application_new ("org.gtk.PrintEditor4", G_APPLICATION_HANDLES_OPEN);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (app),
|
||||
app_entries, G_N_ELEMENTS (app_entries),
|
||||
@@ -840,7 +871,7 @@ main (int argc, char **argv)
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
g_signal_connect (app, "command-line", G_CALLBACK (command_line), NULL);
|
||||
g_signal_connect (app, "open", G_CALLBACK (open), NULL);
|
||||
|
||||
g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
||||
|
||||
@@ -200,18 +200,18 @@
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkStringList" id="name_list">
|
||||
<items>
|
||||
<item>Andrea</item>
|
||||
<item>Otto</item>
|
||||
<item>Orville</item>
|
||||
<item>Benjamin</item>
|
||||
</items>
|
||||
</object>
|
||||
<object class="GtkEntryCompletion" id="name_completion">
|
||||
<property name="model">name_list</property>
|
||||
<property name="model">liststore1</property>
|
||||
<property name="text-column">2</property>
|
||||
<property name="inline-completion">1</property>
|
||||
<property name="popup-single-match">0</property>
|
||||
<property name="inline-selection">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText"/>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="lrmodel">
|
||||
<columns>
|
||||
|
||||
@@ -378,7 +378,6 @@ gdk_device_get_state
|
||||
gdk_device_get_surface_at_position
|
||||
GdkTimeCoord
|
||||
gdk_device_get_axis
|
||||
gdk_device_get_axis_names
|
||||
|
||||
<SUBSECTION>
|
||||
gdk_device_tool_get_serial
|
||||
@@ -483,6 +482,7 @@ gdk_event_get_source_device
|
||||
gdk_event_get_device_tool
|
||||
gdk_event_get_time
|
||||
gdk_event_get_display
|
||||
gdk_event_get_seat
|
||||
GdkEventSequence
|
||||
gdk_event_get_event_sequence
|
||||
gdk_event_get_modifier_state
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
<chapter id="Lists">
|
||||
<title>GListModel support</title>
|
||||
<xi:include href="xml/gtkbitset.xml" />
|
||||
<xi:include href="xml/gtkexpression.xml" />
|
||||
<xi:include href="xml/gtkfilterlistmodel.xml" />
|
||||
<section>
|
||||
@@ -72,7 +73,6 @@
|
||||
<xi:include href="xml/gtknoselection.xml" />
|
||||
<xi:include href="xml/gtksingleselection.xml" />
|
||||
<xi:include href="xml/gtkmultiselection.xml" />
|
||||
<xi:include href="xml/gtkpropertyselection.xml" />
|
||||
</section>
|
||||
<xi:include href="xml/gtkbookmarklist.xml" />
|
||||
<xi:include href="xml/gtkdirectorylist.xml" />
|
||||
|
||||
@@ -312,6 +312,8 @@ gtk_list_box_bind_model
|
||||
gtk_list_box_row_new
|
||||
gtk_list_box_row_changed
|
||||
gtk_list_box_row_is_selected
|
||||
gtk_list_box_row_get_child
|
||||
gtk_list_box_row_set_child
|
||||
gtk_list_box_row_get_header
|
||||
gtk_list_box_row_set_header
|
||||
gtk_list_box_row_get_index
|
||||
@@ -339,21 +341,69 @@ gtk_list_box_get_type
|
||||
gtk_list_box_row_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkbitset</FILE>
|
||||
<TITLE>GtkBitset</TITLE>
|
||||
GtkBitset
|
||||
gtk_bitset_ref
|
||||
gtk_bitset_unref
|
||||
gtk_bitset_new_empty
|
||||
gtk_bitset_new_range
|
||||
gtk_bitset_copy
|
||||
<SUBSECTION>
|
||||
gtk_bitset_contains
|
||||
gtk_bitset_is_empty
|
||||
gtk_bitset_equals
|
||||
gtk_bitset_get_minimum
|
||||
gtk_bitset_get_maximum
|
||||
gtk_bitset_get_size
|
||||
gtk_bitset_get_size_in_range
|
||||
gtk_bitset_get_nth
|
||||
<SUBSECTION>
|
||||
gtk_bitset_remove_all
|
||||
gtk_bitset_add
|
||||
gtk_bitset_remove
|
||||
gtk_bitset_add_range
|
||||
gtk_bitset_remove_range
|
||||
gtk_bitset_add_range_closed
|
||||
gtk_bitset_remove_range_closed
|
||||
gtk_bitset_add_rectangle
|
||||
gtk_bitset_remove_rectangle
|
||||
gtk_bitset_union
|
||||
gtk_bitset_intersect
|
||||
gtk_bitset_subtract
|
||||
gtk_bitset_difference
|
||||
gtk_bitset_shift_left
|
||||
gtk_bitset_shift_right
|
||||
gtk_bitset_slice
|
||||
<SUBSECTION>
|
||||
GtkBitsetIter
|
||||
gtk_bitset_iter_init_first
|
||||
gtk_bitset_iter_init_last
|
||||
gtk_bitset_iter_init_at
|
||||
gtk_bitset_iter_next
|
||||
gtk_bitset_iter_previous
|
||||
gtk_bitset_iter_get_value
|
||||
gtk_bitset_iter_is_valid
|
||||
<SUBSECTION Private>
|
||||
GTK_TYPE_BITSET
|
||||
gtk_bitset_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkselectionmodel</FILE>
|
||||
<TITLE>GtkSelectionModel</TITLE>
|
||||
GtkSelectionModel
|
||||
gtk_selection_model_is_selected
|
||||
gtk_selection_model_get_selection
|
||||
gtk_selection_model_get_selection_in_range
|
||||
gtk_selection_model_select_item
|
||||
gtk_selection_model_unselect_item
|
||||
gtk_selection_model_select_range
|
||||
gtk_selection_model_unselect_range
|
||||
gtk_selection_model_select_all
|
||||
gtk_selection_model_unselect_all
|
||||
GtkSelectionCallback
|
||||
gtk_selection_model_select_callback
|
||||
gtk_selection_model_unselect_callback
|
||||
gtk_selection_model_query_range
|
||||
gtk_selection_model_set_selection
|
||||
<SUBSECTION>
|
||||
gtk_selection_model_selection_changed
|
||||
<SUBSECTION Standard>
|
||||
@@ -404,17 +454,6 @@ gtk_multi_selection_new
|
||||
gtk_multi_selection_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkpropertyselection</FILE>
|
||||
<TITLE>GtkPropertySelection</TITLE>
|
||||
GtkPropertySelection
|
||||
gtk_property_selection_new
|
||||
gtk_property_selection_get_model
|
||||
gtk_property_selection_get_property
|
||||
<SUBSECTION Private>
|
||||
gtk_property_selection_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtklistitem</FILE>
|
||||
<TITLE>GtkListItem</TITLE>
|
||||
@@ -426,6 +465,8 @@ gtk_list_item_set_child
|
||||
gtk_list_item_get_selected
|
||||
gtk_list_item_get_selectable
|
||||
gtk_list_item_set_selectable
|
||||
gtk_list_item_get_activatable
|
||||
gtk_list_item_set_activatable
|
||||
<SUBSECTION Standard>
|
||||
GTK_LIST_ITEM
|
||||
GTK_LIST_ITEM_CLASS
|
||||
@@ -589,6 +630,7 @@ gtk_column_view_column_get_type
|
||||
<TITLE>GtkGridView</TITLE>
|
||||
GtkGridView
|
||||
gtk_grid_view_new
|
||||
gtk_grid_view_new_with_factory
|
||||
gtk_grid_view_set_model
|
||||
gtk_grid_view_get_model
|
||||
gtk_grid_view_set_max_columns
|
||||
@@ -599,6 +641,8 @@ gtk_grid_view_set_single_click_activate
|
||||
gtk_grid_view_get_single_click_activate
|
||||
gtk_grid_view_set_enable_rubberband
|
||||
gtk_grid_view_get_enable_rubberband
|
||||
gtk_grid_view_set_factory
|
||||
gtk_grid_view_get_factory
|
||||
<SUBSECTION Standard>
|
||||
GTK_GRID_VIEW
|
||||
GTK_GRID_VIEW_CLASS
|
||||
@@ -1162,20 +1206,24 @@ gtk_entry_buffer_get_type
|
||||
<FILE>gtkentrycompletion</FILE>
|
||||
<TITLE>GtkEntryCompletion</TITLE>
|
||||
GtkEntryCompletion
|
||||
GtkEntryCompletionMatchFunc
|
||||
gtk_entry_completion_new
|
||||
gtk_entry_completion_new_with_area
|
||||
gtk_entry_completion_get_entry
|
||||
gtk_entry_completion_set_model
|
||||
gtk_entry_completion_get_model
|
||||
gtk_entry_completion_set_expression
|
||||
gtk_entry_completion_get_expression
|
||||
gtk_entry_completion_set_factory
|
||||
gtk_entry_completion_get_factory
|
||||
gtk_entry_completion_set_match_func
|
||||
gtk_entry_completion_set_minimum_key_length
|
||||
gtk_entry_completion_get_minimum_key_length
|
||||
gtk_entry_completion_compute_prefix
|
||||
gtk_entry_completion_complete
|
||||
gtk_entry_completion_get_completion_prefix
|
||||
gtk_entry_completion_insert_prefix
|
||||
gtk_entry_completion_insert_action_text
|
||||
gtk_entry_completion_insert_action_markup
|
||||
gtk_entry_completion_delete_action
|
||||
gtk_entry_completion_set_text_column
|
||||
gtk_entry_completion_get_text_column
|
||||
gtk_entry_completion_set_inline_completion
|
||||
gtk_entry_completion_get_inline_completion
|
||||
gtk_entry_completion_set_inline_selection
|
||||
@@ -1434,8 +1482,6 @@ gtk_filter_get_strictness
|
||||
<SUBSECTION>
|
||||
GtkFilterChange
|
||||
gtk_filter_changed
|
||||
<SUBSECTION>
|
||||
gtk_custom_filter_new
|
||||
<SUBSECTION Standard>
|
||||
GTK_FILTER
|
||||
GTK_IS_FILTER
|
||||
@@ -1453,6 +1499,7 @@ gtk_filter_get_type
|
||||
GtkCustomFilter
|
||||
GtkCustomFilterFunc
|
||||
gtk_custom_filter_new
|
||||
gtk_custom_filter_set_filter_func
|
||||
<SUBSECTION Standard>
|
||||
GTK_CUSTOM_FILTER
|
||||
GTK_IS_CUSTOM_FILTER
|
||||
@@ -1497,6 +1544,9 @@ 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
|
||||
@@ -1516,6 +1566,9 @@ gtk_fixed_new
|
||||
gtk_fixed_put
|
||||
gtk_fixed_remove
|
||||
gtk_fixed_move
|
||||
gtk_fixed_get_child_position
|
||||
gtk_fixed_get_child_transform
|
||||
gtk_fixed_set_child_transform
|
||||
<SUBSECTION Standard>
|
||||
GTK_FIXED
|
||||
GTK_IS_FIXED
|
||||
@@ -2729,6 +2782,8 @@ gtk_numeric_sorter_get_type
|
||||
<TITLE>GtkCustomSorter</TITLE>
|
||||
GtkCustomSorter
|
||||
gtk_custom_sorter_new
|
||||
|
||||
gtk_custom_sorter_set_sort_func
|
||||
<SUBSECTION Standard>
|
||||
GTK_CUSTOM_SORTER
|
||||
GTK_IS_CUSTOM_SORTER
|
||||
|
||||
@@ -18,6 +18,7 @@ gtk_aspect_frame_get_type
|
||||
gtk_assistant_get_type
|
||||
gtk_assistant_page_get_type
|
||||
gtk_bin_layout_get_type
|
||||
gtk_bitset_get_type
|
||||
gtk_bookmark_list_get_type
|
||||
gtk_box_get_type
|
||||
gtk_box_layout_get_type
|
||||
@@ -171,7 +172,6 @@ gtk_print_operation_preview_get_type
|
||||
gtk_print_settings_get_type
|
||||
@DISABLE_ON_W32@gtk_print_unix_dialog_get_type
|
||||
gtk_progress_bar_get_type
|
||||
gtk_property_selection_get_type
|
||||
gtk_radio_button_get_type
|
||||
gtk_range_get_type
|
||||
gtk_recent_manager_get_type
|
||||
|
||||
@@ -176,7 +176,6 @@ private_headers = [
|
||||
'gtkroundedboxprivate.h',
|
||||
'gtkscalerprivate.h',
|
||||
'gtksearchentryprivate.h',
|
||||
'gtkset.h',
|
||||
'gtksettingsprivate.h',
|
||||
'gtkshortcutcontrollerprivate.h',
|
||||
'gtkshortcutsshortcutprivate.h',
|
||||
@@ -216,6 +215,7 @@ private_headers = [
|
||||
'gtkwin32themeprivate.h',
|
||||
'gtkwindowprivate.h',
|
||||
'gtk-text-input-client-protocol.h',
|
||||
'roaring.h',
|
||||
]
|
||||
|
||||
images = [
|
||||
|
||||
@@ -457,6 +457,11 @@ as property. GtkNotebook and GtkAssistant are similar.
|
||||
gtk4-builder-tool can help with this conversion, with the --3to4 option
|
||||
of the simplify command.
|
||||
|
||||
### Adapt to GtkScrolledWindow API changes
|
||||
|
||||
The constructor for GtkScrolledWindow no longer takes the adjustments
|
||||
as arguments - these were almost always %NULL.
|
||||
|
||||
### Adapt to GtkBin removal
|
||||
|
||||
The abstract base class GtkBin for single-child containers has been
|
||||
@@ -638,7 +643,7 @@ nodes.
|
||||
|
||||
If you are using a #GtkDrawingArea for custom drawing, you need to switch
|
||||
to using gtk_drawing_area_set_draw_func() to set a draw function instead
|
||||
of connnecting a handler to the #GtkWidget::draw signal.
|
||||
of connecting a handler to the #GtkWidget::draw signal.
|
||||
|
||||
### Stop using APIs to query GdkSurfaces
|
||||
|
||||
@@ -940,3 +945,18 @@ You can replace calls to <function>gtk_dialog_run()</function>
|
||||
by specifying that the #GtkDialog must be modal using
|
||||
gtk_window_set_modal() or the %GTK_DIALOG_MODAL flag, and
|
||||
connecting to the #GtkDialog::response signal.
|
||||
|
||||
## Changes to consider after the switch
|
||||
|
||||
GTK 4 has a number of new features that you may want to take
|
||||
advantage of once the dust has settled over the initial migration.
|
||||
|
||||
### Consider porting to the new list widgets
|
||||
|
||||
In GTK 2 and 3, GtkTreeModel and GtkCellRenderer and widgets using
|
||||
these were the primary way of displaying data and lists. GTK 4 brings
|
||||
a new family of widgets for this purpose that uses list models instead
|
||||
of tree models, and widgets instead of cell renderers.
|
||||
|
||||
To learn more about the new list widgets, you can read the [List Widget
|
||||
Overview](#ListWidget).
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
GTK inspects a number of environment variables in addition to
|
||||
standard variables like `LANG`, `PATH`, `HOME` or `DISPLAY`; mostly
|
||||
to determine paths to look for certain files. The [X11]{#x11-envar},
|
||||
[Windows]{#win32-envar} and [Broadway]{#broadway-envar} GDK backends
|
||||
use some additional environment variables.
|
||||
to determine paths to look for certain files. The [X11](#x11-envar),
|
||||
[Wayland](#wayland-envar), [Windows](#win32-envar) and
|
||||
[Broadway](#broadway-envar) GDK backends use some additional
|
||||
environment variables.
|
||||
|
||||
### GTK_DEBUG {#GTK_Debug-Options}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ GTK provides powerful widgets to display and edit lists of data. This document
|
||||
gives an overview over the concepts and how they work together to allow
|
||||
developers to implement lists.
|
||||
|
||||
Lists are intended to be used whenever developers want to display lists of
|
||||
objects in roughly the same way.
|
||||
Lists are intended to be used whenever developers want to display many objects
|
||||
in roughly the same way.
|
||||
|
||||
Lists are perfectly fine to be used for very short list of only 2 or 3 elements,
|
||||
but generally scale fine to millions of items. Of course, the larger the list
|
||||
@@ -32,8 +32,8 @@ be provided in 3 ways or combinations thereof:
|
||||
specific data, like #GtkDirectoryList. And there are models like #GListStore
|
||||
that allow building lists manually.
|
||||
|
||||
* Wrapping list models exists like #GtkFilterListModel or #GtkSortListModel
|
||||
that modify or adapt or combine other models.
|
||||
* Wrapping list models like #GtkFilterListModel or #GtkSortListModel
|
||||
modify, adapt or combine other models.
|
||||
|
||||
* Last but not least, developers are encouraged to create their own #GListModel
|
||||
implementations. The interface is kept deliberately small to make this easy.
|
||||
@@ -44,8 +44,9 @@ multiple different models at once.
|
||||
The elements in a model are called **_items_**. All items are #GObjects.
|
||||
|
||||
Every item in a model has a **_position_** which is the unsigned integer that
|
||||
describes where in the model the item is located. This position can of course
|
||||
change as items are added or removed from the model.
|
||||
describes where in the model the item is located. The first item in a model is
|
||||
at position 0. The position of an item can of course change as other items are
|
||||
added or removed from the model.
|
||||
|
||||
It is important to be aware of the difference between items and positions
|
||||
because the mapping from position to item is not permanent, so developers
|
||||
@@ -80,7 +81,7 @@ The behavior of selection models - ie which items they allow selecting and
|
||||
what effect this has on other items - is completely up to the selection model.
|
||||
As such, single-selections, multi-selections or sharing selection state between
|
||||
different selection models and/or views is possible. The selection state of an
|
||||
item is exposed in the listitem via the GtkListItem:selected property.
|
||||
item is exposed in the listitem via the #GtkListItem:selected property.
|
||||
|
||||
Views and listitems also support activation. Activation means that double
|
||||
clicking or pressing enter while inside a focused row will cause the view
|
||||
|
||||
@@ -7,4 +7,13 @@ the Wayland backend by setting `GDK_BACKEND=wayland`.
|
||||
On UNIX, the Wayland backend is enabled by default, so you don't need to
|
||||
do anything special when compiling it, and everything should "just work."
|
||||
|
||||
Currently, the Wayland backend does not use any additional environment variables.
|
||||
## Wayland-specific environment variables {#wayland-envar}
|
||||
|
||||
### WAYLAND_DISPLAY
|
||||
|
||||
Specifies the name of the Wayland display to use. Typically, wayland-0
|
||||
or wayland-1.
|
||||
|
||||
### XDG_RUNTIME_DIR
|
||||
|
||||
Used to locate the Wayland socket to use.
|
||||
|
||||
@@ -16,7 +16,6 @@ variables.
|
||||
### GDK_IGNORE_WINTAB
|
||||
|
||||
If this variable is set, GTK doesn't use the Wintab API for tablet support.
|
||||
</para>
|
||||
|
||||
### GDK_USE_WINTAB
|
||||
|
||||
@@ -37,10 +36,10 @@ can override GTK settings in the `settings.ini` file or at runtime in the
|
||||
GTK Inspector.
|
||||
|
||||
Themes are loaded from normal Windows variants of the XDG locations:
|
||||
`%HOME%/icons/THEME/cursors`,
|
||||
`%APPDATA%/icons/THEME/cursors`,
|
||||
`%HOME%/icons/THEME/cursors`,
|
||||
`%APPDATA%/icons/THEME/cursors`,
|
||||
`RUNTIME_PREFIX/share/icons/THEME/cursors`
|
||||
|
||||
The `gtk-cursor-theme-size`> setting is ignored, GTK will use
|
||||
The `gtk-cursor-theme-size` setting is ignored, GTK will use
|
||||
the cursor size that Windows tells it to use.
|
||||
|
||||
|
||||
@@ -40,4 +40,15 @@ void gdk_surface_set_widget (GdkSurface *surface,
|
||||
gpointer widget);
|
||||
gpointer gdk_surface_get_widget (GdkSurface *surface);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *key;
|
||||
guint value;
|
||||
const char *help;
|
||||
} GdkDebugKey;
|
||||
|
||||
guint gdk_parse_debug_var (const char *variable,
|
||||
const GdkDebugKey *keys,
|
||||
guint nkeys);
|
||||
|
||||
#endif /* __GDK__PRIVATE_H__ */
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <fribidi.h>
|
||||
|
||||
@@ -128,28 +130,28 @@ static int gdk_initialized = 0; /* 1 if the library is initi
|
||||
*/
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static const GDebugKey gdk_debug_keys[] = {
|
||||
{ "misc", GDK_DEBUG_MISC },
|
||||
{ "events", GDK_DEBUG_EVENTS },
|
||||
{ "dnd", GDK_DEBUG_DND },
|
||||
{ "input", GDK_DEBUG_INPUT },
|
||||
{ "eventloop", GDK_DEBUG_EVENTLOOP },
|
||||
{ "frames", GDK_DEBUG_FRAMES },
|
||||
{ "settings", GDK_DEBUG_SETTINGS },
|
||||
{ "opengl", GDK_DEBUG_OPENGL },
|
||||
{ "vulkan", GDK_DEBUG_VULKAN },
|
||||
{ "selection", GDK_DEBUG_SELECTION },
|
||||
{ "clipboard", GDK_DEBUG_CLIPBOARD },
|
||||
{ "nograbs", GDK_DEBUG_NOGRABS },
|
||||
{ "gl-disable", GDK_DEBUG_GL_DISABLE },
|
||||
{ "gl-software", GDK_DEBUG_GL_SOFTWARE },
|
||||
{ "gl-texture-rect", GDK_DEBUG_GL_TEXTURE_RECT },
|
||||
{ "gl-legacy", GDK_DEBUG_GL_LEGACY },
|
||||
{ "gl-gles", GDK_DEBUG_GL_GLES },
|
||||
{ "gl-debug", GDK_DEBUG_GL_DEBUG },
|
||||
{ "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE },
|
||||
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE },
|
||||
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS },
|
||||
static const GdkDebugKey gdk_debug_keys[] = {
|
||||
{ "misc", GDK_DEBUG_MISC, "Miscellaneous information" },
|
||||
{ "events", GDK_DEBUG_EVENTS, "Information about events" },
|
||||
{ "dnd", GDK_DEBUG_DND, "Information about Drag-and-Drop" },
|
||||
{ "input", GDK_DEBUG_INPUT, "Information about input (Windows)" },
|
||||
{ "eventloop", GDK_DEBUG_EVENTLOOP, "Information about event loop operation (Quartz)" },
|
||||
{ "frames", GDK_DEBUG_FRAMES, "Information about the frame clock" },
|
||||
{ "settings", GDK_DEBUG_SETTINGS, "Information about xsettings" },
|
||||
{ "opengl", GDK_DEBUG_OPENGL, "Information about OpenGL" },
|
||||
{ "vulkan", GDK_DEBUG_VULKAN, "Information about Vulkan" },
|
||||
{ "selection", GDK_DEBUG_SELECTION, "Information about selections" },
|
||||
{ "clipboard", GDK_DEBUG_CLIPBOARD, "Information about clipboards" },
|
||||
{ "nograbs", GDK_DEBUG_NOGRABS, "Disable pointer and keyboard grabs (X11)" },
|
||||
{ "gl-disable", GDK_DEBUG_GL_DISABLE, "Disable OpenGL support" },
|
||||
{ "gl-software", GDK_DEBUG_GL_SOFTWARE, "Force OpenGL software rendering" },
|
||||
{ "gl-texture-rect", GDK_DEBUG_GL_TEXTURE_RECT, "Use OpenGL texture rectangle extension" },
|
||||
{ "gl-legacy", GDK_DEBUG_GL_LEGACY, "Use a legacy OpenGL context" },
|
||||
{ "gl-gles", GDK_DEBUG_GL_GLES, "Use a GLES OpenGL context" },
|
||||
{ "gl-debug", GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" },
|
||||
{ "vulkan-disable", GDK_DEBUG_VULKAN_DISABLE, "Disable Vulkan support" },
|
||||
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer" },
|
||||
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings" },
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -199,6 +201,93 @@ gdk_ensure_resources (void)
|
||||
g_once (®ister_resources_once, register_resources, NULL);
|
||||
}
|
||||
|
||||
guint
|
||||
gdk_parse_debug_var (const char *variable,
|
||||
const GdkDebugKey *keys,
|
||||
guint nkeys)
|
||||
{
|
||||
guint i;
|
||||
guint result = 0;
|
||||
const char *string;
|
||||
const gchar *p;
|
||||
const gchar *q;
|
||||
gboolean invert;
|
||||
gboolean help;
|
||||
|
||||
string = g_getenv (variable);
|
||||
if (string == NULL)
|
||||
return 0;
|
||||
|
||||
p = string;
|
||||
invert = FALSE;
|
||||
help = FALSE;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
q = strpbrk (p, ":;, \t");
|
||||
if (!q)
|
||||
q = p + strlen (p);
|
||||
|
||||
if (3 == q - p && g_ascii_strncasecmp ("all", p, q - p) == 0)
|
||||
{
|
||||
invert = TRUE;
|
||||
}
|
||||
else if (4 == q - p && g_ascii_strncasecmp ("help", p, q - p) == 0)
|
||||
{
|
||||
help = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < nkeys; i++)
|
||||
{
|
||||
if (strlen (keys[i].key) == q - p &&
|
||||
g_ascii_strncasecmp (keys[i].key, p, q - p) == 0)
|
||||
{
|
||||
result |= keys[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == nkeys)
|
||||
{
|
||||
char *val = g_strndup (p, q - p);
|
||||
fprintf (stderr, "Unrecognized value \"%s\". Try %s=help\n", val, variable);
|
||||
g_free (val);
|
||||
}
|
||||
}
|
||||
|
||||
p = q;
|
||||
if (*p)
|
||||
p++;
|
||||
}
|
||||
|
||||
if (help)
|
||||
{
|
||||
int max_width = 4;
|
||||
for (i = 0; i < nkeys; i++)
|
||||
max_width = MAX (max_width, strlen (keys[i].key));
|
||||
max_width += 4;
|
||||
|
||||
fprintf (stderr, "Supported %s values:\n", variable);
|
||||
for (i = 0; i < nkeys; i++)
|
||||
fprintf (stderr, " %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
|
||||
fprintf (stderr, " %s%*s%s\n", "all", max_width - 3, " ", "Enable all values");
|
||||
fprintf (stderr, " %s%*s%s\n", "help", max_width - 4, " ", "Print this help");
|
||||
fprintf (stderr, "\nMultiple values can be given, separated by : or space.\n");
|
||||
}
|
||||
|
||||
if (invert)
|
||||
{
|
||||
guint all_flags = 0;
|
||||
|
||||
for (i = 0; i < nkeys; i++)
|
||||
all_flags |= keys[i].value;
|
||||
|
||||
result = all_flags & (~result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_pre_parse (void)
|
||||
{
|
||||
@@ -207,13 +296,12 @@ gdk_pre_parse (void)
|
||||
gdk_ensure_resources ();
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
gchar *debug_string = getenv("GDK_DEBUG");
|
||||
if (debug_string != NULL)
|
||||
_gdk_debug_flags = g_parse_debug_string (debug_string,
|
||||
(GDebugKey *) gdk_debug_keys,
|
||||
G_N_ELEMENTS (gdk_debug_keys));
|
||||
}
|
||||
_gdk_debug_flags = gdk_parse_debug_var ("GDK_DEBUG",
|
||||
gdk_debug_keys,
|
||||
G_N_ELEMENTS (gdk_debug_keys));
|
||||
#else
|
||||
if (g_getenv ("GDK_DEBUG"))
|
||||
g_warning ("GDK_DEBUG set but ignored because GTK isn't built with G_ENABLE_DEBUG");
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
|
||||
if (g_getenv ("GTK_TRACE_FD"))
|
||||
|
||||
+4
-6
@@ -43,14 +43,12 @@ typedef struct _GdkTimeCoord GdkTimeCoord;
|
||||
* @GDK_SOURCE_CURSOR: the device is a graphics tablet “puck” or similar device.
|
||||
* @GDK_SOURCE_KEYBOARD: the device is a keyboard.
|
||||
* @GDK_SOURCE_TOUCHSCREEN: the device is a direct-input touch device, such
|
||||
* as a touchscreen or tablet. This device type has been added in 3.4.
|
||||
* as a touchscreen or tablet
|
||||
* @GDK_SOURCE_TOUCHPAD: the device is an indirect touch device, such
|
||||
* as a touchpad. This device type has been added in 3.4.
|
||||
* @GDK_SOURCE_TRACKPOINT: the device is a trackpoint. This device type has been
|
||||
* added in 3.22
|
||||
* as a touchpad
|
||||
* @GDK_SOURCE_TRACKPOINT: the device is a trackpoint
|
||||
* @GDK_SOURCE_TABLET_PAD: the device is a "pad", a collection of buttons,
|
||||
* rings and strips found in drawing tablets. This device type has been
|
||||
* added in 3.22.
|
||||
* rings and strips found in drawing tablets
|
||||
*
|
||||
* An enumeration describing the type of an input device in general terms.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1187,7 +1187,7 @@ gdk_event_get_surface (GdkEvent *event)
|
||||
|
||||
/**
|
||||
* gdk_event_get_seat:
|
||||
* @event: a #GdkEvent.
|
||||
* @event: a #GdkEvent
|
||||
*
|
||||
* Returns the seat that originated the event.
|
||||
*
|
||||
|
||||
@@ -2079,6 +2079,9 @@ gdk_wayland_display_get_setting (GdkDisplay *display,
|
||||
{
|
||||
TranslationEntry *entry;
|
||||
|
||||
if (GDK_DISPLAY_DEBUG_CHECK (display, DEFAULT_SETTINGS))
|
||||
return FALSE;
|
||||
|
||||
if (GDK_WAYLAND_DISPLAY (display)->settings != NULL &&
|
||||
g_hash_table_size (GDK_WAYLAND_DISPLAY (display)->settings) == 0)
|
||||
return FALSE;
|
||||
|
||||
+19
-20
@@ -1,21 +1,22 @@
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gdk/gdk-private.h"
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static const GDebugKey gsk_debug_keys[] = {
|
||||
{ "renderer", GSK_DEBUG_RENDERER },
|
||||
{ "cairo", GSK_DEBUG_CAIRO },
|
||||
{ "opengl", GSK_DEBUG_OPENGL },
|
||||
{ "shaders", GSK_DEBUG_SHADERS },
|
||||
{ "surface", GSK_DEBUG_SURFACE },
|
||||
{ "vulkan", GSK_DEBUG_VULKAN },
|
||||
{ "fallback", GSK_DEBUG_FALLBACK },
|
||||
{ "glyphcache", GSK_DEBUG_GLYPH_CACHE },
|
||||
{ "diff", GSK_DEBUG_DIFF },
|
||||
{ "geometry", GSK_DEBUG_GEOMETRY },
|
||||
{ "full-redraw", GSK_DEBUG_FULL_REDRAW},
|
||||
{ "sync", GSK_DEBUG_SYNC },
|
||||
{ "vulkan-staging-image", GSK_DEBUG_VULKAN_STAGING_IMAGE },
|
||||
{ "vulkan-staging-buffer", GSK_DEBUG_VULKAN_STAGING_BUFFER }
|
||||
static const GdkDebugKey gsk_debug_keys[] = {
|
||||
{ "renderer", GSK_DEBUG_RENDERER, "General renderer information" },
|
||||
{ "cairo", GSK_DEBUG_CAIRO, "Cairo renderer information" },
|
||||
{ "opengl", GSK_DEBUG_OPENGL, "OpenGL renderer information" },
|
||||
{ "vulkan", GSK_DEBUG_VULKAN, "Vulkan renderer information" },
|
||||
{ "shaders", GSK_DEBUG_SHADERS, "Information about shaders" },
|
||||
{ "surface", GSK_DEBUG_SURFACE, "Information about surfaces" },
|
||||
{ "fallback", GSK_DEBUG_FALLBACK, "Information about fallbacks" },
|
||||
{ "glyphcache", GSK_DEBUG_GLYPH_CACHE, "Information about glyph caching" },
|
||||
{ "diff", GSK_DEBUG_DIFF, "Show differences" },
|
||||
{ "geometry", GSK_DEBUG_GEOMETRY, "Show borders" },
|
||||
{ "full-redraw", GSK_DEBUG_FULL_REDRAW, "Force full redraws" },
|
||||
{ "sync", GSK_DEBUG_SYNC, "Sync after each frame" },
|
||||
{ "vulkan-staging-image", GSK_DEBUG_VULKAN_STAGING_IMAGE, "Use a staging image for Vulkan texture upload" },
|
||||
{ "vulkan-staging-buffer", GSK_DEBUG_VULKAN_STAGING_BUFFER, "Use a staging buffer for Vulkan texture upload" }
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -29,11 +30,9 @@ init_debug_flags (void)
|
||||
|
||||
if (g_once_init_enter (&gsk_debug_flags__set))
|
||||
{
|
||||
const char *env = g_getenv ("GSK_DEBUG");
|
||||
|
||||
gsk_debug_flags = g_parse_debug_string (env,
|
||||
(GDebugKey *) gsk_debug_keys,
|
||||
G_N_ELEMENTS (gsk_debug_keys));
|
||||
gsk_debug_flags = gdk_parse_debug_var ("GSK_DEBUG",
|
||||
gsk_debug_keys,
|
||||
G_N_ELEMENTS (gsk_debug_keys));
|
||||
|
||||
g_once_init_leave (&gsk_debug_flags__set, TRUE);
|
||||
}
|
||||
|
||||
@@ -269,3 +269,11 @@
|
||||
...
|
||||
fun:g_quark_*
|
||||
}
|
||||
{
|
||||
glib GQuark
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite
|
||||
fun:malloc
|
||||
...
|
||||
fun:g_intern_static_string
|
||||
}
|
||||
|
||||
@@ -295,7 +295,6 @@ gtk_cell_accessible_action_do_action (AtkAction *action,
|
||||
GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
|
||||
GtkCellAccessibleParent *parent;
|
||||
|
||||
cell = GTK_CELL_ACCESSIBLE (action);
|
||||
if (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)) == NULL)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ static gunichar
|
||||
gtk_password_entry_accessible_get_character_at_offset (AtkText *atk_text,
|
||||
gint offset)
|
||||
{
|
||||
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
|
||||
GtkText *text;
|
||||
char *contents, *index;
|
||||
gunichar result;
|
||||
|
||||
|
||||
@@ -44,9 +44,11 @@
|
||||
#include <gtk/gtkappchooserbutton.h>
|
||||
#include <gtk/gtkapplication.h>
|
||||
#include <gtk/gtkapplicationwindow.h>
|
||||
#include <gtk/gtkarraystore.h>
|
||||
#include <gtk/gtkaspectframe.h>
|
||||
#include <gtk/gtkassistant.h>
|
||||
#include <gtk/gtkbinlayout.h>
|
||||
#include <gtk/gtkbitset.h>
|
||||
#include <gtk/gtkbookmarklist.h>
|
||||
#include <gtk/gtkborder.h>
|
||||
#include <gtk/gtkboxlayout.h>
|
||||
@@ -200,7 +202,6 @@
|
||||
#include <gtk/gtkprintoperationpreview.h>
|
||||
#include <gtk/gtkprintsettings.h>
|
||||
#include <gtk/gtkprogressbar.h>
|
||||
#include <gtk/gtkpropertyselection.h>
|
||||
#include <gtk/gtkradiobutton.h>
|
||||
#include <gtk/gtkrange.h>
|
||||
#include <gtk/gtkrecentmanager.h>
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
#ifndef __GTK_ARRAY_IMPL_PRIVATE_H__
|
||||
#define __GTK_ARRAY_IMPL_PRIVATE_H__
|
||||
|
||||
|
||||
/* This is a dumbed-down GPtrArray, which takes some stack
|
||||
* space to use. When using this, the general case should always
|
||||
* be that the number of elements is lower than reserved_size.
|
||||
* The GPtrArray should only be used in extreme cases.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint reserved_size;
|
||||
guint len;
|
||||
void **stack_space;
|
||||
GPtrArray *ptr_array;
|
||||
|
||||
} GtkArray;
|
||||
|
||||
|
||||
static inline void
|
||||
gtk_array_init (GtkArray *self,
|
||||
void **stack_space,
|
||||
guint reserved_size)
|
||||
{
|
||||
self->reserved_size = reserved_size;
|
||||
self->len = 0;
|
||||
self->stack_space = stack_space;
|
||||
self->ptr_array = NULL;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
gtk_array_index (const GtkArray *self,
|
||||
guint index)
|
||||
{
|
||||
g_assert (index < self->len);
|
||||
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
return self->stack_space[index];
|
||||
|
||||
return g_ptr_array_index (self->ptr_array, index);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_add (GtkArray *self,
|
||||
void *element)
|
||||
{
|
||||
if (G_LIKELY (self->len < self->reserved_size))
|
||||
{
|
||||
self->stack_space[self->len] = element;
|
||||
self->len++;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Need to fall back to the GPtrArray */
|
||||
if (G_UNLIKELY (!self->ptr_array))
|
||||
{
|
||||
self->ptr_array = g_ptr_array_new_full (self->len + 1, NULL);
|
||||
memcpy (self->ptr_array->pdata, self->stack_space, sizeof (void *) * self->len);
|
||||
self->ptr_array->len = self->len;
|
||||
}
|
||||
|
||||
g_ptr_array_add (self->ptr_array, element);
|
||||
self->len++; /* We still count self->len */
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_insert (GtkArray *self,
|
||||
guint index,
|
||||
void *element)
|
||||
{
|
||||
if (index >= self->len)
|
||||
{
|
||||
gtk_array_add (self, element);
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_LIKELY (self->len < self->reserved_size))
|
||||
{
|
||||
memmove (self->stack_space + index + 1, self->stack_space + index,
|
||||
sizeof (void *) * (self->len - index));
|
||||
self->stack_space[index] = element;
|
||||
self->len++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!self->ptr_array))
|
||||
{
|
||||
self->ptr_array = g_ptr_array_new_full (self->len + 1, NULL);
|
||||
memcpy (self->ptr_array->pdata, self->stack_space, sizeof (void *) * self->len);
|
||||
self->ptr_array->len = self->len;
|
||||
}
|
||||
|
||||
g_assert (self->ptr_array);
|
||||
g_ptr_array_insert (self->ptr_array, index, element);
|
||||
self->len++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_array_free (GtkArray *self,
|
||||
GDestroyNotify element_free_func)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
{
|
||||
if (element_free_func)
|
||||
{
|
||||
for (i = 0; i < self->len; i++)
|
||||
element_free_func (self->stack_space[i]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert (self->ptr_array);
|
||||
|
||||
if (element_free_func)
|
||||
{
|
||||
for (i = 0; i < self->ptr_array->len; i++)
|
||||
element_free_func (g_ptr_array_index (self->ptr_array, i));
|
||||
}
|
||||
|
||||
g_ptr_array_free (self->ptr_array, TRUE);
|
||||
}
|
||||
|
||||
static inline void **
|
||||
gtk_array_get_data (GtkArray *self)
|
||||
{
|
||||
if (G_LIKELY (!self->ptr_array))
|
||||
return self->stack_space;
|
||||
|
||||
return self->ptr_array->pdata;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkarraystore.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GObject *
|
||||
#define GTK_VECTOR_FREE_FUNC g_object_unref
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkarraystore
|
||||
* @title: GtkArrayStore
|
||||
* @short_description: A simple array implementation of #GListModel
|
||||
*
|
||||
* #GtkArrayStore is a simple implementation of #GListModel that stores all
|
||||
* items in memory.
|
||||
*
|
||||
* It provides appending, deletions, and lookups in O(1) time and insertions
|
||||
* in O(N) time. it is implemented using an array.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GtkArrayStore:
|
||||
*
|
||||
* #GtkArrayStore is an opaque data structure and can only be accessed
|
||||
* using the following functions.
|
||||
**/
|
||||
|
||||
struct _GtkArrayStore
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GType item_type;
|
||||
GtkVector items;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ITEM_TYPE,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static void gtk_array_store_iface_init (GListModelInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkArrayStore, gtk_array_store, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_array_store_iface_init));
|
||||
|
||||
static void
|
||||
gtk_array_store_dispose (GObject *object)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
gtk_vector_clear (&self->items);
|
||||
|
||||
G_OBJECT_CLASS (gtk_array_store_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ITEM_TYPE: /* construct-only */
|
||||
g_assert (g_type_is_a (g_value_get_gtype (value), G_TYPE_OBJECT));
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_class_init (GtkArrayStoreClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_array_store_dispose;
|
||||
object_class->get_property = gtk_array_store_get_property;
|
||||
object_class->set_property = gtk_array_store_set_property;
|
||||
|
||||
/**
|
||||
* GtkArrayStore:item-type:
|
||||
*
|
||||
* The type of items contained in this list self. Items must be
|
||||
* subclasses of #GObject.
|
||||
**/
|
||||
g_object_class_install_property (object_class, PROP_ITEM_TYPE,
|
||||
g_param_spec_gtype ("item-type", "", "", G_TYPE_OBJECT,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static GType
|
||||
gtk_array_store_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
return self->item_type;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_array_store_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
return gtk_vector_get_size (&self->items);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_array_store_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkArrayStore *self = GTK_ARRAY_STORE (list);
|
||||
|
||||
if (position >= gtk_vector_get_size (&self->items))
|
||||
return NULL;
|
||||
|
||||
return g_object_ref (gtk_vector_get (&self->items, position));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_iface_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_array_store_get_item_type;
|
||||
iface->get_n_items = gtk_array_store_get_n_items;
|
||||
iface->get_item = gtk_array_store_get_item;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_store_init (GtkArrayStore *self)
|
||||
{
|
||||
gtk_vector_init (&self->items);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_new:
|
||||
* @item_type: the #GType of items in the list
|
||||
*
|
||||
* Creates a new #GtkArrayStore with items of type @item_type. @item_type
|
||||
* must be a subclass of #GObject.
|
||||
*
|
||||
* Returns: a new #GtkArrayStore
|
||||
*/
|
||||
GtkArrayStore *
|
||||
gtk_array_store_new (GType item_type)
|
||||
{
|
||||
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_ARRAY_STORE,
|
||||
"item-type", item_type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_append:
|
||||
* @self: a #GtkArrayStore
|
||||
* @item: (type GObject): the new item
|
||||
*
|
||||
* Appends @item to @self. @item must be of type #GtkArrayStore:item-type.
|
||||
*
|
||||
* This function takes a ref on @item.
|
||||
*
|
||||
* Use gtk_array_store_splice() to append multiple items at the same time
|
||||
* efficiently.
|
||||
*/
|
||||
void
|
||||
gtk_array_store_append (GtkArrayStore *self,
|
||||
gpointer item)
|
||||
{
|
||||
guint position;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (item), self->item_type));
|
||||
|
||||
position = gtk_vector_get_size (&self->items);
|
||||
gtk_vector_append (&self->items, g_object_ref (item));
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_remove_all:
|
||||
* @self: a #GtkArrayStore
|
||||
*
|
||||
* Removes all items from @self.
|
||||
*
|
||||
* Since: 2.44
|
||||
*/
|
||||
void
|
||||
gtk_array_store_remove_all (GtkArrayStore *self)
|
||||
{
|
||||
guint n_items;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
|
||||
n_items = gtk_vector_get_size (&self->items);
|
||||
gtk_vector_clear (&self->items);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), 0, n_items, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_array_store_splice:
|
||||
* @self: a #GtkArrayStore
|
||||
* @position: the position at which to make the change
|
||||
* @n_removals: the number of items to remove
|
||||
* @additions: (array length=n_additions) (element-type GObject): the items to add
|
||||
* @n_additions: the number of items to add
|
||||
*
|
||||
* Changes @self by removing @n_removals items and adding @n_additions
|
||||
* items to it. @additions must contain @n_additions items of type
|
||||
* #GtkArrayStore:item-type. %NULL is not permitted.
|
||||
*
|
||||
* This function is more efficient than gtk_array_store_insert() and
|
||||
* gtk_array_store_remove(), because it only emits
|
||||
* #GListModel::items-changed once for the change.
|
||||
*
|
||||
* This function takes a ref on each item in @additions.
|
||||
*
|
||||
* The parameters @position and @n_removals must be correct (ie:
|
||||
* @position + @n_removals must be less than or equal to the length of
|
||||
* the list at the time this function is called).
|
||||
*
|
||||
* Since: 2.44
|
||||
*/
|
||||
void
|
||||
gtk_array_store_splice (GtkArrayStore *self,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
gpointer *additions,
|
||||
guint n_additions)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (GTK_IS_ARRAY_STORE (self));
|
||||
g_return_if_fail (position + n_removals >= position); /* overflow */
|
||||
g_return_if_fail (position + n_removals <= gtk_vector_get_size (&self->items));
|
||||
|
||||
for (i = 0; i < n_additions; i++)
|
||||
g_object_ref (additions[i]);
|
||||
|
||||
gtk_vector_splice (&self->items, position, n_removals, (GObject **) additions, n_additions);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_ARRAY_STORE_H__
|
||||
#define __GTK_ARRAY_STORE_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_ARRAY_STORE (gtk_array_store_get_type ())
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE(GtkArrayStore, gtk_array_store, GTK, ARRAY_STORE, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkArrayStore * gtk_array_store_new (GType item_type);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_append (GtkArrayStore *store,
|
||||
gpointer item);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_remove_all (GtkArrayStore *store);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_array_store_splice (GtkArrayStore *store,
|
||||
guint position,
|
||||
guint n_removals,
|
||||
gpointer *additions,
|
||||
guint n_additions);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_ARRAY_STORE_H__ */
|
||||
+958
@@ -0,0 +1,958 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
|
||||
#include "roaring.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkbitset
|
||||
* @title: GtkBitset
|
||||
* @short_description: Sets of integers
|
||||
* @see_also: GtkSelectionModel
|
||||
*
|
||||
* #GtkBitset is a data structure for representing a set of unsigned integers.
|
||||
* Another name for this data structure is "bitmap".
|
||||
*
|
||||
* This version is based on [roaring bitmaps](https://roaringbitmap.org/).
|
||||
*
|
||||
* A bitset allows adding a set of integers and provides support for set operations
|
||||
* like unions, intersections and checks for equality or if a value is contained
|
||||
* in the set. #GtkBitset also contains various functions to query metadata about
|
||||
* the bitset, such as the minimum or maximum values or its size.
|
||||
*
|
||||
* The fastest way to iterate values in a bitset is #GtkBitsetIter which allows
|
||||
* quick iteration of all the values in a bitset.
|
||||
*
|
||||
* The main use case for #GtkBitset is implementing complex selections for
|
||||
* #GtkSelectionModel.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GtkBitset: (ref-func gtk_bitset_ref) (unref-func gtk_bitset_unref)
|
||||
*
|
||||
* The `GtkBitset` structure contains only private data.
|
||||
*/
|
||||
struct _GtkBitset
|
||||
{
|
||||
int ref_count;
|
||||
roaring_bitmap_t roaring;
|
||||
};
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GtkBitset, gtk_bitset,
|
||||
gtk_bitset_ref,
|
||||
gtk_bitset_unref)
|
||||
|
||||
/**
|
||||
* gtk_bitset_ref:
|
||||
* @self: (allow-none): a #GtkBitset
|
||||
*
|
||||
* Acquires a reference on the given #GtkBitset.
|
||||
*
|
||||
* Returns: (transfer none): the #GtkBitset with an additional reference
|
||||
*/
|
||||
GtkBitset *
|
||||
gtk_bitset_ref (GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
self->ref_count += 1;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_unref:
|
||||
* @self: (allow-none): a #GtkBitset
|
||||
*
|
||||
* Releases a reference on the given #GtkBitset.
|
||||
*
|
||||
* If the reference was the last, the resources associated to the @self are
|
||||
* freed.
|
||||
*/
|
||||
void
|
||||
gtk_bitset_unref (GtkBitset *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (self->ref_count > 0);
|
||||
|
||||
self->ref_count -= 1;
|
||||
if (self->ref_count > 0)
|
||||
return;
|
||||
|
||||
ra_clear (&self->roaring.high_low_container);
|
||||
g_slice_free (GtkBitset, self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_contains:
|
||||
* @self: a #GtkBitset
|
||||
* @value: the value to check
|
||||
*
|
||||
* Checks if the given @value has been added to @bitset
|
||||
*
|
||||
* Returns: %TRUE if @self contains @value
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_contains (const GtkBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_contains (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_is_empty:
|
||||
* @self: a #GtkBitset
|
||||
*
|
||||
* Check if no value is contained in bitset.
|
||||
*
|
||||
* Returns: %TRUE if @self is empty
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_is_empty (const GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, TRUE);
|
||||
|
||||
return roaring_bitmap_is_empty (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_equals:
|
||||
* @self: a #GtkBitset
|
||||
* @other: another #GtkBitset
|
||||
*
|
||||
* Returns %TRUE if @self and @other contain the same values.
|
||||
*
|
||||
* Returns: %TRUE if @self and @other contain the same values
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_equals (const GtkBitset *self,
|
||||
const GtkBitset *other)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, other == NULL);
|
||||
g_return_val_if_fail (other != NULL, FALSE);
|
||||
|
||||
if (self == other)
|
||||
return TRUE;
|
||||
|
||||
return roaring_bitmap_equals (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_minimum:
|
||||
* @self: a #GtkBitset
|
||||
*
|
||||
* Returns the smallest value in @self. If @self is empty,
|
||||
* G_MAXUINT is returned.
|
||||
*
|
||||
* Returns: The smallest value in @self
|
||||
**/
|
||||
guint
|
||||
gtk_bitset_get_minimum (const GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, G_MAXUINT);
|
||||
|
||||
return roaring_bitmap_minimum (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_maximum:
|
||||
* @self: a #GtkBitset
|
||||
*
|
||||
* Returns the largest value in @self. If @self is empty,
|
||||
* 0 is returned.
|
||||
*
|
||||
* Returns: The largest value in @self
|
||||
**/
|
||||
guint
|
||||
gtk_bitset_get_maximum (const GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return roaring_bitmap_maximum (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_size:
|
||||
* @self: a #GtkBitSet
|
||||
*
|
||||
* Gets the number of values that were added to the set.
|
||||
* For example, if the set is empty, 0 is returned.
|
||||
*
|
||||
* Note that this function returns a #guint64, because when all values are
|
||||
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set.
|
||||
**/
|
||||
guint64
|
||||
gtk_bitset_get_size (const GtkBitset *self)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
|
||||
return roaring_bitmap_get_cardinality (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_size_in_range:
|
||||
* @self: a #GtkBitSet
|
||||
* @first: the first element to include
|
||||
* @last: the last element to include
|
||||
*
|
||||
* Gets the number of values that are part of the set from @first to @last
|
||||
* (inclusive).
|
||||
*
|
||||
* Note that this function returns a #guint64, because when all values are
|
||||
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||
*
|
||||
* Returns: The number of values in the set from @first to @last.
|
||||
**/
|
||||
guint64
|
||||
gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, 0);
|
||||
g_return_val_if_fail (last >= first, 0);
|
||||
|
||||
return roaring_bitmap_range_cardinality (&self->roaring, first, ((uint64_t) last) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_get_nth:
|
||||
* @self: a #GtkBitset
|
||||
* @nth: index of the item to get
|
||||
*
|
||||
* Returns the value of the @nth item in self.
|
||||
*
|
||||
* If @nth is >= the size of @self, 0 is returned.
|
||||
*
|
||||
* Returns: the value of the @nth item in @self
|
||||
**/
|
||||
guint
|
||||
gtk_bitset_get_nth (const GtkBitset *self,
|
||||
guint nth)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
if (!roaring_bitmap_select (&self->roaring, nth, &result))
|
||||
return 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_new_empty:
|
||||
*
|
||||
* Creates a new empty bitset.
|
||||
*
|
||||
* Returns: A new empty bitset
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_new_empty (void)
|
||||
{
|
||||
GtkBitset *self;
|
||||
|
||||
self = g_slice_new0 (GtkBitset);
|
||||
|
||||
self->ref_count = 1;
|
||||
|
||||
ra_init (&self->roaring.high_low_container);
|
||||
|
||||
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
|
||||
*
|
||||
* Creates a copy of @self.
|
||||
*
|
||||
* Returns: (transfer full): A new bitset that contains the same
|
||||
* values as @self
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_bitset_copy (const GtkBitset *self)
|
||||
{
|
||||
GtkBitset *copy;
|
||||
|
||||
g_return_val_if_fail (self != NULL, NULL);
|
||||
|
||||
copy = gtk_bitset_new_empty ();
|
||||
roaring_bitmap_overwrite (©->roaring, &self->roaring);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_remove_all:
|
||||
* @self: a #GtkBitset
|
||||
*
|
||||
* Removes all values from the bitset so that it is empty again.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_remove_all (GtkBitset *self)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_add:
|
||||
* @self: a #GtkBitset
|
||||
* @value: value to add
|
||||
*
|
||||
* Adds @value to @self if it wasn't part of it before.
|
||||
*
|
||||
* Returns: %TRUE if @value was not part of @self and @self
|
||||
* was changed.
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_add (GtkBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_add_checked (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_remove:
|
||||
* @self: a #GtkBitset
|
||||
* @value: value to add
|
||||
*
|
||||
* Removes @value from @self if it was part of it before.
|
||||
*
|
||||
* Returns: %TRUE if @value was part of @self and @self
|
||||
* was changed.
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_remove (GtkBitset *self,
|
||||
guint value)
|
||||
{
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
|
||||
return roaring_bitmap_remove_checked (&self->roaring, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_add_range:
|
||||
* @self: a #GtkBitset
|
||||
* @start: first value to add
|
||||
* @n_items: number of consecutive values to add
|
||||
*
|
||||
* Adds all values from @start (inclusive) to @start + @n_items
|
||||
* (exclusive) in @self.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_add_range (GtkBitset *self,
|
||||
guint start,
|
||||
guint n_items)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
/* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */
|
||||
g_return_if_fail (start + n_items == 0 || start + n_items > start);
|
||||
|
||||
roaring_bitmap_add_range_closed (&self->roaring, start, start + n_items - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_remove_range:
|
||||
* @self: a #GtkBitset
|
||||
* @start: first value to remove
|
||||
* @n_items: number of consecutive values to remove
|
||||
*
|
||||
* Removes all values from @start (inclusive) to @start + @n_items (exclusive)
|
||||
* in @self.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_remove_range (GtkBitset *self,
|
||||
guint start,
|
||||
guint n_items)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
/* overflow check, the == 0 is to allow add_range(G_MAXUINT, 1); */
|
||||
g_return_if_fail (start + n_items == 0 || start + n_items > start);
|
||||
|
||||
roaring_bitmap_remove_range_closed (&self->roaring, start, start + n_items - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_add_range_closed:
|
||||
* @self: a #GtkBitset
|
||||
* @first: first value to add
|
||||
* @last: last value to add
|
||||
*
|
||||
* Adds the closed range [@first, @last], so @first, @last and all
|
||||
* values inbetween. @first must be smaller than @last.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_add_range_closed (GtkBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (first <= last);
|
||||
|
||||
roaring_bitmap_add_range_closed (&self->roaring, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_remove_range_closed:
|
||||
* @self: a #GtkBitset
|
||||
* @first: first value to remove
|
||||
* @last: last value to remove
|
||||
*
|
||||
* Removes the closed range [@first, @last], so @first, @last and all
|
||||
* values inbetween. @first must be smaller than @last.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_remove_range_closed (GtkBitset *self,
|
||||
guint first,
|
||||
guint last)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (first <= last);
|
||||
|
||||
roaring_bitmap_remove_range_closed (&self->roaring, first, last);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_add_rectangle:
|
||||
* @self: a #GtkBitset
|
||||
* @start: first value to add
|
||||
* @width: width of the rectangle
|
||||
* @height: height of the rectangle
|
||||
* @stride: row stride of the grid
|
||||
*
|
||||
* Interprets the values as a 2-dimensional boolean grid with the given @stride
|
||||
* and inside that grid, adds a rectangle with the given @width and @height.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_add_rectangle (GtkBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail ((start % stride) + width <= stride);
|
||||
g_return_if_fail (G_MAXUINT - start >= height * stride);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
gtk_bitset_add_range (self, i * stride + start, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_remove_rectangle:
|
||||
* @self: a #GtkBitset
|
||||
* @start: first value to remove
|
||||
* @width: width of the rectangle
|
||||
* @height: height of the rectangle
|
||||
* @stride: row stride of the grid
|
||||
*
|
||||
* Interprets the values as a 2-dimensional boolean grid with the given @stride
|
||||
* and inside that grid, removes a rectangle with the given @width and @height.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_remove_rectangle (GtkBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride)
|
||||
{
|
||||
guint i;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (width <= stride);
|
||||
g_return_if_fail (G_MAXUINT - start >= height * stride);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
gtk_bitset_remove_range (self, i * stride + start, width);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_union:
|
||||
* @self: a #GtkBitset
|
||||
* @other: the #GtkBitset to union with
|
||||
*
|
||||
* Sets @self to be the union of @self and @other, that is add all values
|
||||
* from @other into @self that weren't part of it.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. Nothing will
|
||||
* happen in that case.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_union (GtkBitset *self,
|
||||
const GtkBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
roaring_bitmap_or_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_intersect:
|
||||
* @self: a #GtkBitset
|
||||
* @other: the #GtkBitset to intersect with
|
||||
*
|
||||
* Sets @self to be the intersection of @self and @other, that is remove
|
||||
* all values from @self that are not part of @other.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. Nothing will
|
||||
* happen in that case.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_intersect (GtkBitset *self,
|
||||
const GtkBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
return;
|
||||
|
||||
roaring_bitmap_and_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_subtract:
|
||||
* @self: a #GtkBitset
|
||||
* @other: the #GtkBitset to subtract
|
||||
*
|
||||
* Sets @self to be the subtraction of @other from @self, that is remove
|
||||
* all values from @self that are part of @other.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. The bitset
|
||||
* will be emptied in that case.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_subtract (GtkBitset *self,
|
||||
const GtkBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
return;
|
||||
}
|
||||
|
||||
roaring_bitmap_andnot_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_difference:
|
||||
* @self: a #GtkBitset
|
||||
* @other: the #GtkBitset to compute the difference from
|
||||
*
|
||||
* Sets @self to be the symmetric difference of @self and @other, that
|
||||
* is set @self to contain all values that were either contained in @self
|
||||
* or in @other, but not in both.
|
||||
* This operation is also called an XOR.
|
||||
*
|
||||
* It is allowed for @self and @other to be the same bitset. The bitset
|
||||
* will be emptied in that case.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_difference (GtkBitset *self,
|
||||
const GtkBitset *other)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (other != NULL);
|
||||
|
||||
if (self == other)
|
||||
{
|
||||
roaring_bitmap_clear (&self->roaring);
|
||||
return;
|
||||
}
|
||||
|
||||
roaring_bitmap_xor_inplace (&self->roaring, &other->roaring);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_shift_left:
|
||||
* @self: a $GtkBitset
|
||||
* @amount: amount to shift all values to the left
|
||||
*
|
||||
* Shifts all values in @self to the left by @amount. Values
|
||||
* smaller than @amount are discarded.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_shift_left (GtkBitset *self,
|
||||
guint amount)
|
||||
{
|
||||
GtkBitset *original;
|
||||
GtkBitsetIter iter;
|
||||
guint value;
|
||||
gboolean loop;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (amount == 0)
|
||||
return;
|
||||
|
||||
original = gtk_bitset_copy (self);
|
||||
gtk_bitset_remove_all (self);
|
||||
|
||||
for (loop = gtk_bitset_iter_init_at (&iter, original, amount, &value);
|
||||
loop;
|
||||
loop = gtk_bitset_iter_next (&iter, &value))
|
||||
{
|
||||
gtk_bitset_add (self, value - amount);
|
||||
}
|
||||
|
||||
gtk_bitset_unref (original);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_shift_right:
|
||||
* @self: a $GtkBitset
|
||||
* @amount: amount to shift all values to the right
|
||||
*
|
||||
* Shifts all values in @self to the right by @amount. Values
|
||||
* that end up too large to be held in a #guint are discarded.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_shift_right (GtkBitset *self,
|
||||
guint amount)
|
||||
{
|
||||
GtkBitset *original;
|
||||
GtkBitsetIter iter;
|
||||
guint value;
|
||||
gboolean loop;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
|
||||
if (amount == 0)
|
||||
return;
|
||||
|
||||
original = gtk_bitset_copy (self);
|
||||
gtk_bitset_remove_all (self);
|
||||
|
||||
for (loop = gtk_bitset_iter_init_first (&iter, original, &value);
|
||||
loop && value <= G_MAXUINT - amount;
|
||||
loop = gtk_bitset_iter_next (&iter, &value))
|
||||
{
|
||||
gtk_bitset_add (self, value + amount);
|
||||
}
|
||||
|
||||
gtk_bitset_unref (original);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_slice:
|
||||
* @self: a #GtkBitset
|
||||
* @position: position at which to slice
|
||||
* @removed: number of values to remove
|
||||
* @added: number of values to add
|
||||
*
|
||||
* This is a support function for #GListModel handling, by mirroring
|
||||
* the #GlistModel::items-changed signal.
|
||||
*
|
||||
* First, it "cuts" the values from @position to @removed from
|
||||
* the bitset. That is, it removes all those values and shifts
|
||||
* all larger values to the left by @removed places.
|
||||
*
|
||||
* Then, it "pastes" new room into the bitset by shifting all values
|
||||
* larger than @position by @added spaces to the right. This frees
|
||||
* up space that can then be filled.
|
||||
**/
|
||||
void
|
||||
gtk_bitset_slice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added)
|
||||
{
|
||||
g_return_if_fail (self != NULL);
|
||||
/* overflow */
|
||||
g_return_if_fail (position + removed >= position);
|
||||
g_return_if_fail (position + added >= position);
|
||||
|
||||
gtk_bitset_remove_range (self, position, removed);
|
||||
|
||||
if (removed != added)
|
||||
{
|
||||
GtkBitset *shift = gtk_bitset_copy (self);
|
||||
|
||||
gtk_bitset_remove_range (shift, 0, position);
|
||||
gtk_bitset_remove_range (self, position, G_MAXUINT - position + 1);
|
||||
if (added > removed)
|
||||
gtk_bitset_shift_right (shift, added - removed);
|
||||
else
|
||||
gtk_bitset_shift_left (shift, removed - added);
|
||||
gtk_bitset_union (self, shift);
|
||||
gtk_bitset_unref (shift);
|
||||
}
|
||||
}
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GtkBitsetIter) >= sizeof (roaring_uint32_iterator_t));
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_init_first:
|
||||
* @iter: (out): a pointer to an uninitialized #GtkBitsetIter
|
||||
* @set: a #GtkBitset
|
||||
* @value: (out) (optional): Set to the first value in @set
|
||||
*
|
||||
* Initializes an iterator for @set and points it to the first
|
||||
* value in @set. If @set is empty, %FALSE is returned and @value
|
||||
* is set to %G_MAXUINT.
|
||||
*
|
||||
* Returns: %TRUE if @set isn't empty.
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_init_first (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator (&set->roaring, riter);
|
||||
|
||||
if (value)
|
||||
*value = riter->has_value ? riter->current_value : 0;
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_init_last:
|
||||
* @iter: (out): a pointer to an uninitialized #GtkBitsetIter
|
||||
* @set: a #GtkBitset
|
||||
* @value: (out) (optional): Set to the last value in @set
|
||||
*
|
||||
* Initializes an iterator for @set and points it to the last
|
||||
* value in @set. If @set is empty, %FALSE is returned.
|
||||
*
|
||||
* Returns: %TRUE if @set isn't empty.
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_init_last (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator_last (&set->roaring, riter);
|
||||
|
||||
if (value)
|
||||
*value = riter->has_value ? riter->current_value : 0;
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_init_at:
|
||||
* @iter: (out): a pointer to an uninitialized #GtkBitsetIter
|
||||
* @set: a #GtkBitset
|
||||
* @target: target value to start iterating at
|
||||
* @value: (out) (optional): Set to the found value in @set
|
||||
*
|
||||
* Initializes @iter to point to @target. If @target is not found, finds
|
||||
* the next value after it. If no value >= @target exists in @set, this
|
||||
* function returns %FALSE.
|
||||
*
|
||||
* Returns: %TRUE if a value was found.
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_init_at (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint target,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (set != NULL, FALSE);
|
||||
|
||||
roaring_init_iterator (&set->roaring, riter);
|
||||
if (!roaring_move_uint32_iterator_equalorlarger (riter, target))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_next:
|
||||
* @iter: a pointer to a valid #GtkBitsetIter
|
||||
* @value: (out) (optional): Set to the next value
|
||||
*
|
||||
* Moves @iter to the next value in the set. If it was already
|
||||
* pointing to the last value in the set, %FALSE is returned and
|
||||
* @iter is invalidated.
|
||||
*
|
||||
* Returns: %TRUE if a next value existed
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_next (GtkBitsetIter *iter,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
if (!roaring_advance_uint32_iterator (riter))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_previous:
|
||||
* @iter: a pointer to a valid #GtkBitsetIter
|
||||
* @value: (out) (optional): Set to the previous value
|
||||
*
|
||||
* Moves @iter to the previous value in the set. If it was already
|
||||
* pointing to the first value in the set, %FALSE is returned and
|
||||
* @iter is invalidated.
|
||||
*
|
||||
* Returns: %TRUE if a previous value existed
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_previous (GtkBitsetIter *iter,
|
||||
guint *value)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
if (!roaring_previous_uint32_iterator (riter))
|
||||
{
|
||||
if (value)
|
||||
*value = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (value)
|
||||
*value = riter->current_value;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_get_value:
|
||||
* @iter: a #GtkBitsetIter
|
||||
*
|
||||
* Gets the current value that @iter points to.
|
||||
*
|
||||
* If @iter is not valid and gtk_bitset_iter_is_valid() returns
|
||||
* %FALSE, this function returns 0.
|
||||
*
|
||||
* Returns: The current value pointer to by @iter
|
||||
**/
|
||||
guint
|
||||
gtk_bitset_iter_get_value (const GtkBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, 0);
|
||||
|
||||
if (!riter->has_value)
|
||||
return 0;
|
||||
|
||||
return riter->current_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_bitset_iter_is_valid:
|
||||
* @iter: a #GtkBitsetIter
|
||||
*
|
||||
* Checks if @iter points to a valid value.
|
||||
*
|
||||
* Returns: %TRUE if @iter points to a valid value
|
||||
**/
|
||||
gboolean
|
||||
gtk_bitset_iter_is_valid (const GtkBitsetIter *iter)
|
||||
{
|
||||
roaring_uint32_iterator_t *riter = (roaring_uint32_iterator_t *) iter;
|
||||
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
|
||||
return riter->has_value;
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GTK_BITSET_H__
|
||||
#define __GTK_BITSET_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_BITSET (gtk_bitset_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_bitset_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_bitset_ref (GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_unref (GtkBitset *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_contains (const GtkBitset *self,
|
||||
guint value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_is_empty (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_equals (const GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint64 gtk_bitset_get_size (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint64 gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_nth (const GtkBitset *self,
|
||||
guint nth);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_minimum (const GtkBitset *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_get_maximum (const GtkBitset *self);
|
||||
|
||||
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);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_add (GtkBitset *self,
|
||||
guint value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_remove (GtkBitset *self,
|
||||
guint value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_add_range (GtkBitset *self,
|
||||
guint start,
|
||||
guint n_items);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_remove_range (GtkBitset *self,
|
||||
guint start,
|
||||
guint n_items);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_add_range_closed (GtkBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_remove_range_closed (GtkBitset *self,
|
||||
guint first,
|
||||
guint last);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_add_rectangle (GtkBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_remove_rectangle (GtkBitset *self,
|
||||
guint start,
|
||||
guint width,
|
||||
guint height,
|
||||
guint stride);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_union (GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_intersect (GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_subtract (GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_difference (GtkBitset *self,
|
||||
const GtkBitset *other);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_shift_left (GtkBitset *self,
|
||||
guint amount);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_shift_right (GtkBitset *self,
|
||||
guint amount);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_bitset_slice (GtkBitset *self,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added);
|
||||
|
||||
typedef struct {gpointer private_data[10]; } GtkBitsetIter;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_init_first (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_init_last (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_init_at (GtkBitsetIter *iter,
|
||||
const GtkBitset *set,
|
||||
guint target,
|
||||
guint *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_next (GtkBitsetIter *iter,
|
||||
guint *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_previous (GtkBitsetIter *iter,
|
||||
guint *value);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gtk_bitset_iter_get_value (const GtkBitsetIter *iter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_bitset_iter_is_valid (const GtkBitsetIter *iter);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_BITSET_H__ */
|
||||
+20
-2
@@ -108,7 +108,7 @@
|
||||
* as %TRUE, strings like “FALSE”, “f”, “no”, “n”, “0” are interpreted
|
||||
* as %FALSE), enumerations (can be specified by their name, nick or
|
||||
* integer value), flags (can be specified by their name, nick, integer
|
||||
* value, optionally combined with “|”, e.g. “GTK_VISIBLE|GTK_REALIZED”)
|
||||
* value, optionally combined with “|”, e.g. “GTK_INPUT_HINT_EMOJI|GTK_INPUT_HINT_LOWERCASE”)
|
||||
* and colors (in a format understood by gdk_rgba_parse()).
|
||||
*
|
||||
* GVariants can be specified in the format understood by g_variant_parse(),
|
||||
@@ -131,7 +131,7 @@
|
||||
* For more information see g_object_bind_property()
|
||||
*
|
||||
* Sometimes it is necessary to refer to widgets which have implicitly
|
||||
* been constructed by GTK+ as part of a composite widget, to set
|
||||
* been constructed by GTK as part of a composite widget, to set
|
||||
* properties on them or to add further children (e.g. the content area
|
||||
* of a #GtkDialog). This can be achieved by setting the “internal-child”
|
||||
* property of the `<child>` element to a true value. Note that #GtkBuilder
|
||||
@@ -225,6 +225,8 @@
|
||||
#include "gtkicontheme.h"
|
||||
#include "gtkiconthemeprivate.h"
|
||||
#include "gdkpixbufutilsprivate.h"
|
||||
#include "gtkdebug.h"
|
||||
|
||||
|
||||
static void gtk_builder_finalize (GObject *object);
|
||||
static void gtk_builder_set_property (GObject *object,
|
||||
@@ -359,6 +361,22 @@ gtk_builder_finalize (GObject *object)
|
||||
g_free (priv->filename);
|
||||
g_free (priv->resource_prefix);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GTK_DEBUG_CHECK (BUILDER_OBJECTS))
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->objects);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
if (G_OBJECT (value)->ref_count == 1)
|
||||
g_message ("builder: %s with id %s unused",
|
||||
G_OBJECT_TYPE_NAME (value), (const char *)key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
g_hash_table_destroy (priv->objects);
|
||||
|
||||
g_slist_free_full (priv->signals, (GDestroyNotify)_free_signal_info);
|
||||
|
||||
+13
-15
@@ -391,9 +391,9 @@ gtk_css_provider_init (GtkCssProvider *css_provider)
|
||||
}
|
||||
|
||||
static void
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkArray *tree_rules)
|
||||
verify_tree_match_results (GtkCssProvider *provider,
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *tree_rules)
|
||||
{
|
||||
#ifdef VERIFY_TREE
|
||||
GtkCssProviderPrivate *priv = gtk_css_provider_get_instance_private (provider);
|
||||
@@ -407,9 +407,9 @@ verify_tree_match_results (GtkCssProvider *provider,
|
||||
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
||||
|
||||
for (j = 0; j < tree_rules->len; j++)
|
||||
for (j = 0; j < gtk_css_selector_matches_get_size (tree_rules); j++)
|
||||
{
|
||||
if (ruleset == gtk_array_index (tree_rules, j))
|
||||
if (ruleset == gtk_css_selector_matches_get (tree_rules, j))
|
||||
{
|
||||
found = TRUE;
|
||||
break;
|
||||
@@ -459,22 +459,21 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||
GtkCssRuleset *ruleset;
|
||||
guint j;
|
||||
int i;
|
||||
GtkArray tree_rules_array;
|
||||
GtkCssRuleset *rules_stack[32];
|
||||
GtkCssSelectorMatches tree_rules;
|
||||
|
||||
if (_gtk_css_selector_tree_is_empty (priv->tree))
|
||||
return;
|
||||
|
||||
gtk_array_init (&tree_rules_array, (void**)rules_stack, 32);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules_array);
|
||||
gtk_css_selector_matches_init (&tree_rules);
|
||||
_gtk_css_selector_tree_match_all (priv->tree, filter, node, &tree_rules);
|
||||
|
||||
if (tree_rules_array.len > 0)
|
||||
if (!gtk_css_selector_matches_is_empty (&tree_rules))
|
||||
{
|
||||
verify_tree_match_results (css_provider, node, &tree_rules_array);
|
||||
verify_tree_match_results (css_provider, node, &tree_rules);
|
||||
|
||||
for (i = tree_rules_array.len - 1; i >= 0; i--)
|
||||
for (i = gtk_css_selector_matches_get_size (&tree_rules) - 1; i >= 0; i--)
|
||||
{
|
||||
ruleset = gtk_array_index (&tree_rules_array, i);
|
||||
ruleset = gtk_css_selector_matches_get (&tree_rules, i);
|
||||
|
||||
if (ruleset->styles == NULL)
|
||||
continue;
|
||||
@@ -493,9 +492,8 @@ gtk_css_style_provider_lookup (GtkStyleProvider *provider,
|
||||
ruleset->styles[j].value);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_array_free (&tree_rules_array, NULL);
|
||||
}
|
||||
gtk_css_selector_matches_clear (&tree_rules);
|
||||
|
||||
if (change)
|
||||
*change = gtk_css_selector_tree_get_change_all (priv->tree, filter, node);
|
||||
|
||||
+17
-20
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "gtkcssprovider.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtkarrayimplprivate.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1500
|
||||
@@ -152,14 +151,14 @@ gtk_css_selector_tree_get_matches (const GtkCssSelectorTree *tree)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_array_insert_sorted (GtkArray *array,
|
||||
gpointer data)
|
||||
gtk_css_selector_matches_insert_sorted (GtkCssSelectorMatches *matches,
|
||||
gpointer data)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < array->len; i++)
|
||||
for (i = 0; i < gtk_css_selector_matches_get_size (matches); i++)
|
||||
{
|
||||
gpointer elem = gtk_array_index (array, i);
|
||||
gpointer elem = gtk_css_selector_matches_get (matches, i);
|
||||
|
||||
if (data == elem)
|
||||
return;
|
||||
@@ -168,7 +167,7 @@ gtk_array_insert_sorted (GtkArray *array,
|
||||
break;
|
||||
}
|
||||
|
||||
gtk_array_insert (array, i, data);
|
||||
gtk_css_selector_matches_splice (matches, i, 0, (gpointer[1]) { data }, 1);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -1877,7 +1876,7 @@ gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
|
||||
|
||||
static void
|
||||
gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
GtkArray *results)
|
||||
GtkCssSelectorMatches *results)
|
||||
{
|
||||
int i;
|
||||
gpointer *matches;
|
||||
@@ -1887,7 +1886,7 @@ gtk_css_selector_tree_found_match (const GtkCssSelectorTree *tree,
|
||||
return;
|
||||
|
||||
for (i = 0; matches[i] != NULL; i++)
|
||||
gtk_array_insert_sorted (results, matches[i]);
|
||||
gtk_css_selector_matches_insert_sorted (results, matches[i]);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1895,7 +1894,7 @@ gtk_css_selector_tree_match (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
gboolean match_filter,
|
||||
GtkCssNode *node,
|
||||
GtkArray *results)
|
||||
GtkCssSelectorMatches *results)
|
||||
{
|
||||
const GtkCssSelectorTree *prev;
|
||||
GtkCssNode *child;
|
||||
@@ -1932,7 +1931,7 @@ void
|
||||
_gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node,
|
||||
GtkArray *out_tree_rules)
|
||||
GtkCssSelectorMatches *out_tree_rules)
|
||||
{
|
||||
const GtkCssSelectorTree *iter;
|
||||
|
||||
@@ -2117,8 +2116,7 @@ subdivide_infos (GByteArray *array,
|
||||
GHashTableIter iter;
|
||||
guint max_count;
|
||||
gpointer key, value;
|
||||
void *exact_matches_stack[8];
|
||||
GtkArray exact_matches_array;
|
||||
GtkCssSelectorMatches exact_matches;
|
||||
gint32 res;
|
||||
guint i;
|
||||
|
||||
@@ -2160,7 +2158,7 @@ subdivide_infos (GByteArray *array,
|
||||
matched_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
remaining_infos = g_alloca (sizeof (GtkCssSelectorRuleSetInfo *) * n_infos);
|
||||
|
||||
gtk_array_init (&exact_matches_array, (void**)exact_matches_stack, 8);
|
||||
gtk_css_selector_matches_init (&exact_matches);
|
||||
for (i = 0; i < n_infos; i++)
|
||||
{
|
||||
GtkCssSelectorRuleSetInfo *info = infos[i];
|
||||
@@ -2171,7 +2169,7 @@ subdivide_infos (GByteArray *array,
|
||||
if (info->current_selector == NULL)
|
||||
{
|
||||
/* Matches current node */
|
||||
gtk_array_add (&exact_matches_array, info->match);
|
||||
gtk_css_selector_matches_append (&exact_matches, info->match);
|
||||
if (info->selector_match != NULL)
|
||||
*info->selector_match = GUINT_TO_POINTER (tree_offset);
|
||||
}
|
||||
@@ -2188,17 +2186,16 @@ subdivide_infos (GByteArray *array,
|
||||
}
|
||||
}
|
||||
|
||||
if (exact_matches_array.len > 0)
|
||||
if (!gtk_css_selector_matches_is_empty (&exact_matches))
|
||||
{
|
||||
gtk_array_add (&exact_matches_array, NULL); /* Null terminate */
|
||||
gtk_css_selector_matches_append (&exact_matches, NULL); /* Null terminate */
|
||||
res = array->len;
|
||||
g_byte_array_append (array, (guint8 *)gtk_array_get_data (&exact_matches_array),
|
||||
exact_matches_array.len * sizeof (gpointer));
|
||||
|
||||
gtk_array_free (&exact_matches_array, NULL);
|
||||
g_byte_array_append (array, (guint8 *) gtk_css_selector_matches_get_data (&exact_matches),
|
||||
gtk_css_selector_matches_get_size (&exact_matches) * sizeof (gpointer));
|
||||
}
|
||||
else
|
||||
res = GTK_CSS_SELECTOR_TREE_EMPTY_OFFSET;
|
||||
gtk_css_selector_matches_clear (&exact_matches);
|
||||
get_tree (array, tree_offset)->matches_offset = res;
|
||||
|
||||
res = subdivide_infos (array, matched_infos, n_matched, tree_offset);
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
#include "gtk/gtkcountingbloomfilterprivate.h"
|
||||
#include "gtk/gtkcsstypesprivate.h"
|
||||
#include "gtk/gtkcssparserprivate.h"
|
||||
#include "gtk/gtkarrayimplprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#define GTK_VECTOR_TYPE_NAME GtkCssSelectorMatches
|
||||
#define GTK_VECTOR_NAME gtk_css_selector_matches
|
||||
#define GTK_VECTOR_PREALLOC 32
|
||||
#include "gtk/gtkvectorimpl.c"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -45,8 +50,8 @@ int _gtk_css_selector_compare (const GtkCssSelector *a,
|
||||
void _gtk_css_selector_tree_free (GtkCssSelectorTree *tree);
|
||||
void _gtk_css_selector_tree_match_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node,
|
||||
GtkArray *out_tree_rules);
|
||||
GtkCssNode *node,
|
||||
GtkCssSelectorMatches *out_tree_rules);
|
||||
GtkCssChange gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
|
||||
const GtkCountingBloomFilter *filter,
|
||||
GtkCssNode *node);
|
||||
|
||||
+8
-8
@@ -45,14 +45,14 @@ typedef enum {
|
||||
GTK_DEBUG_BUILDER = 1 << 7,
|
||||
GTK_DEBUG_SIZE_REQUEST = 1 << 8,
|
||||
GTK_DEBUG_NO_CSS_CACHE = 1 << 9,
|
||||
GTK_DEBUG_SHORTCUTS = 1 << 10,
|
||||
GTK_DEBUG_INTERACTIVE = 1 << 11,
|
||||
GTK_DEBUG_TOUCHSCREEN = 1 << 12,
|
||||
GTK_DEBUG_ACTIONS = 1 << 13,
|
||||
GTK_DEBUG_RESIZE = 1 << 14,
|
||||
GTK_DEBUG_LAYOUT = 1 << 15,
|
||||
GTK_DEBUG_SNAPSHOT = 1 << 16,
|
||||
GTK_DEBUG_CONSTRAINTS = 1 << 17,
|
||||
GTK_DEBUG_INTERACTIVE = 1 << 10,
|
||||
GTK_DEBUG_TOUCHSCREEN = 1 << 11,
|
||||
GTK_DEBUG_ACTIONS = 1 << 12,
|
||||
GTK_DEBUG_RESIZE = 1 << 13,
|
||||
GTK_DEBUG_LAYOUT = 1 << 14,
|
||||
GTK_DEBUG_SNAPSHOT = 1 << 15,
|
||||
GTK_DEBUG_CONSTRAINTS = 1 << 16,
|
||||
GTK_DEBUG_BUILDER_OBJECTS = 1 << 17,
|
||||
} GtkDebugFlag;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
|
||||
+2
-2
@@ -821,7 +821,7 @@ gtk_drop_down_get_selected (GtkDropDown *self)
|
||||
*
|
||||
* Gets the selected item. If no item is selected, %NULL is returned.
|
||||
*
|
||||
* Returns: (transfer none): The selected item
|
||||
* Returns: (transfer none) (type GObject) (nullable): The selected item
|
||||
*/
|
||||
gpointer
|
||||
gtk_drop_down_get_selected_item (GtkDropDown *self)
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+4
-4
@@ -121,7 +121,7 @@
|
||||
* ├── text[.readonly]
|
||||
* ├── image.left
|
||||
* ├── image.right
|
||||
* ├── [progress[.pulse]]
|
||||
* ╰── [progress[.pulse]]
|
||||
* ]|
|
||||
*
|
||||
* GtkEntry has a main node with the name entry. Depending on the properties
|
||||
@@ -1752,7 +1752,7 @@ gtk_entry_size_allocate (GtkWidget *widget,
|
||||
|
||||
completion = gtk_entry_get_completion (entry);
|
||||
if (completion)
|
||||
gtk_entry_completion_resize_popup (completion);
|
||||
_gtk_entry_completion_resize_popup (completion);
|
||||
}
|
||||
|
||||
if (priv->emoji_chooser)
|
||||
@@ -3183,7 +3183,7 @@ gtk_entry_set_completion (GtkEntry *entry,
|
||||
|
||||
if (old)
|
||||
{
|
||||
gtk_entry_completion_disconnect (old);
|
||||
_gtk_entry_completion_disconnect (old);
|
||||
g_object_unref (old);
|
||||
}
|
||||
|
||||
@@ -3196,7 +3196,7 @@ gtk_entry_set_completion (GtkEntry *entry,
|
||||
/* hook into the entry */
|
||||
g_object_ref (completion);
|
||||
|
||||
gtk_entry_completion_connect (completion, entry);
|
||||
_gtk_entry_completion_connect (completion, entry);
|
||||
|
||||
g_object_set_qdata (G_OBJECT (entry), quark_entry_completion, completion);
|
||||
|
||||
|
||||
+644
-428
File diff suppressed because it is too large
Load Diff
+43
-15
@@ -23,8 +23,11 @@
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtklistitemfactory.h>
|
||||
#include <gtk/gtkexpression.h>
|
||||
#include <gtk/gtktreemodel.h>
|
||||
#include <gtk/gtkliststore.h>
|
||||
#include <gtk/gtkcellarea.h>
|
||||
#include <gtk/gtktreeviewcolumn.h>
|
||||
#include <gtk/gtktreemodelfilter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -34,31 +37,50 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkEntryCompletion GtkEntryCompletion;
|
||||
|
||||
/**
|
||||
* GtkEntryCompletionMatchFunc:
|
||||
* @completion: the #GtkEntryCompletion
|
||||
* @key: the string to match, normalized and case-folded
|
||||
* @iter: a #GtkTreeIter indicating the row to match
|
||||
* @user_data: user data given to gtk_entry_completion_set_match_func()
|
||||
*
|
||||
* A function which decides whether the row indicated by @iter matches
|
||||
* a given @key, and should be displayed as a possible completion for @key.
|
||||
* Note that @key is normalized and case-folded (see g_utf8_normalize()
|
||||
* and g_utf8_casefold()). If this is not appropriate, match functions
|
||||
* have access to the unmodified key via
|
||||
* `gtk_editable_get_text (GTK_EDITABLE (gtk_entry_completion_get_entry ()))`.
|
||||
*
|
||||
* Returns: %TRUE if @iter should be displayed as a possible completion
|
||||
* for @key
|
||||
*/
|
||||
typedef gboolean (* GtkEntryCompletionMatchFunc) (GtkEntryCompletion *completion,
|
||||
const gchar *key,
|
||||
GtkTreeIter *iter,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_entry_completion_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkEntryCompletion *gtk_entry_completion_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkEntryCompletion *gtk_entry_completion_new_with_area (GtkCellArea *area);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_entry_completion_get_entry (GtkEntryCompletion *completion);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_completion_set_model (GtkEntryCompletion *completion,
|
||||
GListModel *model);
|
||||
GtkTreeModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_entry_completion_get_model (GtkEntryCompletion *completion);
|
||||
GtkTreeModel *gtk_entry_completion_get_model (GtkEntryCompletion *completion);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_completion_set_expression (GtkEntryCompletion *completion,
|
||||
GtkExpression *expression);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkExpression * gtk_entry_completion_get_expression (GtkEntryCompletion *completion);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_completion_set_factory (GtkEntryCompletion *completion,
|
||||
GtkListItemFactory *factory);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkListItemFactory *gtk_entry_completion_get_factory (GtkEntryCompletion *completion);
|
||||
|
||||
void gtk_entry_completion_set_match_func (GtkEntryCompletion *completion,
|
||||
GtkEntryCompletionMatchFunc func,
|
||||
gpointer func_data,
|
||||
GDestroyNotify func_notify);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_completion_set_minimum_key_length (GtkEntryCompletion *completion,
|
||||
gint length);
|
||||
@@ -100,6 +122,12 @@ gboolean gtk_entry_completion_get_popup_single_match (GtkEntryComplet
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const gchar *gtk_entry_completion_get_completion_prefix (GtkEntryCompletion *completion);
|
||||
/* convenience */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_completion_set_text_column (GtkEntryCompletion *completion,
|
||||
gint column);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gint gtk_entry_completion_get_text_column (GtkEntryCompletion *completion);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
+32
-19
@@ -38,34 +38,43 @@ struct _GtkEntryCompletion
|
||||
|
||||
GtkWidget *entry;
|
||||
|
||||
GListModel *filter_model;
|
||||
GtkExpression *expression;
|
||||
GtkListItemFactory *factory;
|
||||
GtkWidget *tree_view;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkTreeModelFilter *filter_model;
|
||||
GtkCellArea *cell_area;
|
||||
|
||||
GtkEntryCompletionMatchFunc match_func;
|
||||
gpointer match_data;
|
||||
GDestroyNotify match_notify;
|
||||
|
||||
gint minimum_key_length;
|
||||
char *case_normalized_key;
|
||||
gint text_column;
|
||||
|
||||
gchar *case_normalized_key;
|
||||
|
||||
GtkEventController *entry_key_controller;
|
||||
GtkEventController *entry_focus_controller;
|
||||
|
||||
/* only used by GtkEntry when attached: */
|
||||
GtkWidget *popup_window;
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *list_view;
|
||||
|
||||
gulong completion_timeout;
|
||||
gulong changed_id;
|
||||
gulong insert_text_id;
|
||||
|
||||
int current_selected;
|
||||
gint current_selected;
|
||||
|
||||
guint has_completion : 1;
|
||||
guint inline_completion : 1;
|
||||
guint popup_completion : 1;
|
||||
guint popup_set_width : 1;
|
||||
guint first_sel_changed : 1;
|
||||
guint has_completion : 1;
|
||||
guint inline_completion : 1;
|
||||
guint popup_completion : 1;
|
||||
guint popup_set_width : 1;
|
||||
guint popup_single_match : 1;
|
||||
guint inline_selection : 1;
|
||||
guint has_grab : 1;
|
||||
|
||||
char *completion_prefix;
|
||||
gchar *completion_prefix;
|
||||
|
||||
GSource *check_completion_idle;
|
||||
};
|
||||
@@ -75,19 +84,23 @@ struct _GtkEntryCompletionClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
gboolean (* match_selected) (GtkEntryCompletion *completion,
|
||||
guint position);
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter);
|
||||
void (* action_activated) (GtkEntryCompletion *completion,
|
||||
gint index_);
|
||||
gboolean (* insert_prefix) (GtkEntryCompletion *completion,
|
||||
const char *prefix);
|
||||
const gchar *prefix);
|
||||
gboolean (* cursor_on_match) (GtkEntryCompletion *completion,
|
||||
guint position);
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter);
|
||||
void (* no_matches) (GtkEntryCompletion *completion);
|
||||
};
|
||||
|
||||
void gtk_entry_completion_resize_popup (GtkEntryCompletion *completion);
|
||||
void gtk_entry_completion_popdown (GtkEntryCompletion *completion);
|
||||
void gtk_entry_completion_connect (GtkEntryCompletion *completion,
|
||||
GtkEntry *entry);
|
||||
void gtk_entry_completion_disconnect (GtkEntryCompletion *completion);
|
||||
void _gtk_entry_completion_resize_popup (GtkEntryCompletion *completion);
|
||||
void _gtk_entry_completion_popdown (GtkEntryCompletion *completion);
|
||||
void _gtk_entry_completion_connect (GtkEntryCompletion *completion,
|
||||
GtkEntry *entry);
|
||||
void _gtk_entry_completion_disconnect (GtkEntryCompletion *completion);
|
||||
|
||||
GtkIMContext * _gtk_entry_get_im_context (GtkEntry *entry);
|
||||
GtkEventController * gtk_entry_get_key_controller (GtkEntry *entry);
|
||||
|
||||
+3
-1
@@ -1961,7 +1961,7 @@ gtk_expression_bind_notify (gpointer data)
|
||||
* @self: (transfer full): a #GtkExpression
|
||||
* @target: (transfer none) (type GObject): the target object to bind to
|
||||
* @property: name of the property on @target to bind to
|
||||
* @this_: (transfer none) (type GObject): the this argument for
|
||||
* @this_: (transfer none) (type GObject) (nullable): the this argument for
|
||||
* the evaluation of @self
|
||||
*
|
||||
* Bind @target's property named @property to @self.
|
||||
@@ -1992,6 +1992,8 @@ gtk_expression_bind (GtkExpression *self,
|
||||
g_return_val_if_fail (GTK_IS_EXPRESSION (self), NULL);
|
||||
g_return_val_if_fail (G_IS_OBJECT (target), NULL);
|
||||
g_return_val_if_fail (property != NULL, NULL);
|
||||
g_return_val_if_fail (this_ == NULL || G_IS_OBJECT (this_), NULL);
|
||||
|
||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (target), property);
|
||||
if (G_UNLIKELY (pspec == NULL))
|
||||
{
|
||||
|
||||
@@ -102,6 +102,11 @@ static void delete_text_callback (GtkFileChooserEntry *widget,
|
||||
gpointer user_data);
|
||||
#endif
|
||||
|
||||
static gboolean match_selected_callback (GtkEntryCompletion *completion,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkFileChooserEntry *chooser_entry);
|
||||
|
||||
static void set_complete_on_load (GtkFileChooserEntry *chooser_entry,
|
||||
gboolean complete_on_load);
|
||||
static void refresh_current_folder_and_file_part (GtkFileChooserEntry *chooser_entry);
|
||||
@@ -176,6 +181,83 @@ _gtk_file_chooser_entry_class_init (GtkFileChooserEntryClass *class)
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_func (GtkEntryCompletion *compl,
|
||||
const gchar *key,
|
||||
GtkTreeIter *iter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkFileChooserEntry *chooser_entry = user_data;
|
||||
|
||||
/* If we arrive here, the GtkFileSystemModel's GtkFileFilter already filtered out all
|
||||
* files that don't start with the current prefix, so we manually apply the GtkFileChooser's
|
||||
* 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;
|
||||
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
return TRUE;
|
||||
|
||||
needed_flags = gtk_file_filter_get_needed (chooser_entry->current_filter);
|
||||
|
||||
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 TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
chooser_entry_focus_out (GtkEventController *controller,
|
||||
GtkFileChooserEntry *chooser_entry)
|
||||
@@ -187,9 +269,37 @@ static void
|
||||
_gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
GtkEntryCompletion *comp;
|
||||
GtkCellRenderer *cell;
|
||||
|
||||
g_object_set (chooser_entry, "truncate-multiline", TRUE, NULL);
|
||||
|
||||
comp = gtk_entry_completion_new ();
|
||||
gtk_entry_completion_set_popup_single_match (comp, FALSE);
|
||||
gtk_entry_completion_set_minimum_key_length (comp, 0);
|
||||
/* see docs for gtk_entry_completion_set_text_column() */
|
||||
g_object_set (comp, "text-column", FULL_PATH_COLUMN, NULL);
|
||||
|
||||
/* Need a match func here or entry completion uses a wrong one.
|
||||
* We do our own filtering after all. */
|
||||
gtk_entry_completion_set_match_func (comp,
|
||||
match_func,
|
||||
chooser_entry,
|
||||
NULL);
|
||||
|
||||
cell = gtk_cell_renderer_text_new ();
|
||||
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (comp),
|
||||
cell, TRUE);
|
||||
gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (comp),
|
||||
cell,
|
||||
"text", DISPLAY_NAME_COLUMN);
|
||||
|
||||
g_signal_connect (comp, "match-selected",
|
||||
G_CALLBACK (match_selected_callback), chooser_entry);
|
||||
|
||||
gtk_entry_set_completion (GTK_ENTRY (chooser_entry), comp);
|
||||
g_object_unref (comp);
|
||||
|
||||
/* NB: This needs to happen after the completion is set, so this controller
|
||||
* runs before the one installed by entrycompletion */
|
||||
controller = gtk_event_controller_key_new ();
|
||||
@@ -239,6 +349,36 @@ gtk_file_chooser_entry_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (_gtk_file_chooser_entry_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
/* Match functions for the GtkEntryCompletion */
|
||||
static gboolean
|
||||
match_selected_callback (GtkEntryCompletion *completion,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkFileChooserEntry *chooser_entry)
|
||||
{
|
||||
char *path;
|
||||
gint pos;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
FULL_PATH_COLUMN, &path,
|
||||
-1);
|
||||
|
||||
gtk_editable_delete_text (GTK_EDITABLE (chooser_entry),
|
||||
0,
|
||||
gtk_editable_get_position (GTK_EDITABLE (chooser_entry)));
|
||||
pos = 0;
|
||||
gtk_editable_insert_text (GTK_EDITABLE (chooser_entry),
|
||||
path,
|
||||
-1,
|
||||
&pos);
|
||||
|
||||
gtk_editable_set_position (GTK_EDITABLE (chooser_entry), pos);
|
||||
|
||||
g_free (path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_complete_on_load (GtkFileChooserEntry *chooser_entry,
|
||||
gboolean complete_on_load)
|
||||
@@ -412,6 +552,30 @@ gtk_file_chooser_entry_tab_handler (GtkEventControllerKey *key,
|
||||
return GDK_EVENT_STOP;
|
||||
}
|
||||
|
||||
static void
|
||||
update_inline_completion (GtkFileChooserEntry *chooser_entry)
|
||||
{
|
||||
GtkEntryCompletion *completion = gtk_entry_get_completion (GTK_ENTRY (chooser_entry));
|
||||
|
||||
if (!chooser_entry->current_folder_loaded)
|
||||
{
|
||||
gtk_entry_completion_set_inline_completion (completion, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (chooser_entry->action)
|
||||
{
|
||||
case GTK_FILE_CHOOSER_ACTION_OPEN:
|
||||
case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
|
||||
gtk_entry_completion_set_inline_completion (completion, TRUE);
|
||||
break;
|
||||
case GTK_FILE_CHOOSER_ACTION_SAVE:
|
||||
default:
|
||||
gtk_entry_completion_set_inline_completion (completion, FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
discard_completion_store (GtkFileChooserEntry *chooser_entry)
|
||||
{
|
||||
@@ -419,6 +583,7 @@ discard_completion_store (GtkFileChooserEntry *chooser_entry)
|
||||
return;
|
||||
|
||||
gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)), NULL);
|
||||
update_inline_completion (chooser_entry);
|
||||
g_object_unref (chooser_entry->completion_store);
|
||||
chooser_entry->completion_store = NULL;
|
||||
}
|
||||
@@ -482,6 +647,9 @@ populate_completion_store (GtkFileChooserEntry *chooser_entry)
|
||||
chooser_entry->action == GTK_FILE_CHOOSER_ACTION_SAVE);
|
||||
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (chooser_entry->completion_store),
|
||||
DISPLAY_NAME_COLUMN, GTK_SORT_ASCENDING);
|
||||
|
||||
gtk_entry_completion_set_model (gtk_entry_get_completion (GTK_ENTRY (chooser_entry)),
|
||||
chooser_entry->completion_store);
|
||||
}
|
||||
|
||||
/* Callback when the current folder finishes loading */
|
||||
@@ -507,6 +675,7 @@ finished_loading_cb (GtkFileSystemModel *model,
|
||||
gtk_widget_set_tooltip_text (GTK_WIDGET (chooser_entry), NULL);
|
||||
|
||||
completion = gtk_entry_get_completion (GTK_ENTRY (chooser_entry));
|
||||
update_inline_completion (chooser_entry);
|
||||
|
||||
if (gtk_widget_has_focus (GTK_WIDGET (chooser_entry)))
|
||||
{
|
||||
@@ -791,12 +960,32 @@ _gtk_file_chooser_entry_set_action (GtkFileChooserEntry *chooser_entry,
|
||||
|
||||
if (chooser_entry->action != action)
|
||||
{
|
||||
GtkEntryCompletion *comp;
|
||||
|
||||
chooser_entry->action = action;
|
||||
|
||||
comp = gtk_entry_get_completion (GTK_ENTRY (chooser_entry));
|
||||
|
||||
/* FIXME: do we need to actually set the following? */
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GTK_FILE_CHOOSER_ACTION_OPEN:
|
||||
case GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
|
||||
default:
|
||||
gtk_entry_completion_set_popup_single_match (comp, FALSE);
|
||||
break;
|
||||
case GTK_FILE_CHOOSER_ACTION_SAVE:
|
||||
gtk_entry_completion_set_popup_single_match (comp, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chooser_entry->completion_store)
|
||||
_gtk_file_system_model_set_show_files (GTK_FILE_SYSTEM_MODEL (chooser_entry->completion_store),
|
||||
action == GTK_FILE_CHOOSER_ACTION_OPEN ||
|
||||
action == GTK_FILE_CHOOSER_ACTION_SAVE);
|
||||
|
||||
update_inline_completion (chooser_entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+330
-354
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "gtkfilterlistmodel.h"
|
||||
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
@@ -35,30 +35,22 @@
|
||||
* 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_INCREMENTAL,
|
||||
PROP_ITEM_TYPE,
|
||||
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;
|
||||
@@ -67,8 +59,11 @@ struct _GtkFilterListModel
|
||||
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,119 +73,6 @@ 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)
|
||||
{
|
||||
@@ -203,8 +85,6 @@ 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 +95,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 +120,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 +144,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 +160,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 +283,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 +301,22 @@ 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++)
|
||||
{
|
||||
FilterNode *next = gtk_rb_tree_node_get_next (node);
|
||||
if (node->visible)
|
||||
filter_removed++;
|
||||
gtk_rb_tree_remove (self->items, node);
|
||||
node = next;
|
||||
}
|
||||
gtk_bitset_slice (self->matches, position, removed, added);
|
||||
if (self->pending)
|
||||
gtk_bitset_slice (self->pending, position, removed, added);
|
||||
|
||||
filter_added = gtk_filter_list_model_add_items (self, node, position, added);
|
||||
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);
|
||||
|
||||
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),
|
||||
gtk_bitset_get_size_in_range (self->matches, 0, position),
|
||||
filter_removed, filter_added);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -364,6 +333,10 @@ gtk_filter_list_model_set_property (GObject *object,
|
||||
gtk_filter_list_model_set_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_INCREMENTAL:
|
||||
gtk_filter_list_model_set_incremental (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
self->item_type = g_value_get_gtype (value);
|
||||
break;
|
||||
@@ -392,6 +365,10 @@ gtk_filter_list_model_get_property (GObject *object,
|
||||
g_value_set_object (value, self->filter);
|
||||
break;
|
||||
|
||||
case PROP_INCREMENTAL:
|
||||
g_value_set_boolean (value, self->incremental);
|
||||
break;
|
||||
|
||||
case PROP_ITEM_TYPE:
|
||||
g_value_set_gtype (value, self->item_type);
|
||||
break;
|
||||
@@ -400,6 +377,10 @@ gtk_filter_list_model_get_property (GObject *object,
|
||||
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 +393,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 +420,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 +442,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 +482,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 +528,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 +548,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);
|
||||
}
|
||||
@@ -662,6 +574,18 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
GTK_TYPE_FILTER,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:incremental:
|
||||
*
|
||||
* If the model should filter items incrementally
|
||||
*/
|
||||
properties[PROP_INCREMENTAL] =
|
||||
g_param_spec_boolean ("incremental",
|
||||
P_("Incremental"),
|
||||
P_("Filer items incrementally"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkFilterListModel:item-type:
|
||||
*
|
||||
@@ -686,6 +610,18 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
||||
G_TYPE_LIST_MODEL,
|
||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 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);
|
||||
}
|
||||
|
||||
@@ -728,7 +664,7 @@ gtk_filter_list_model_new (GListModel *model,
|
||||
*
|
||||
* 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.
|
||||
* the item type is matches.
|
||||
*
|
||||
* Returns: a new #GtkFilterListModel
|
||||
**/
|
||||
@@ -769,7 +705,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 +764,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 +805,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);
|
||||
}
|
||||
|
||||
@@ -52,6 +52,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
|
||||
|
||||
|
||||
+35
-40
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gtkgridview.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistbaseprivate.h"
|
||||
#include "gtklistitemfactory.h"
|
||||
@@ -452,6 +453,36 @@ gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkBitset *
|
||||
gtk_grid_view_get_items_in_rect (GtkListBase *base,
|
||||
const GdkRectangle *rect)
|
||||
{
|
||||
GtkGridView *self = GTK_GRID_VIEW (base);
|
||||
guint first_row, last_row, first_column, last_column, n_items;
|
||||
GtkBitset *result;
|
||||
|
||||
result = gtk_bitset_new_empty ();
|
||||
|
||||
n_items = gtk_list_base_get_n_items (base);
|
||||
if (n_items == 0)
|
||||
return result;
|
||||
|
||||
first_column = floor (rect->x / self->column_width);
|
||||
last_column = floor ((rect->x + rect->width) / self->column_width);
|
||||
if (!gtk_grid_view_get_cell_at_y (self, rect->y, &first_row, NULL, NULL))
|
||||
first_row = rect->y < 0 ? 0 : n_items - 1;
|
||||
if (!gtk_grid_view_get_cell_at_y (self, rect->y + rect->height, &last_row, NULL, NULL))
|
||||
last_row = rect->y < 0 ? 0 : n_items - 1;
|
||||
|
||||
gtk_bitset_add_rectangle (result,
|
||||
first_row + first_column,
|
||||
last_column - first_column + 1,
|
||||
(last_row - first_row) / self->n_columns + 1,
|
||||
self->n_columns);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_grid_view_move_focus_along (GtkListBase *base,
|
||||
guint pos,
|
||||
@@ -687,43 +718,6 @@ cell_set_size (Cell *cell,
|
||||
gtk_rb_tree_node_mark_dirty (cell);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_grid_view_size_allocate_child (GtkGridView *self,
|
||||
GtkWidget *child,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkAllocation child_allocation;
|
||||
|
||||
if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
child_allocation.x = x;
|
||||
child_allocation.y = y;
|
||||
child_allocation.width = width;
|
||||
child_allocation.height = height;
|
||||
}
|
||||
else if (_gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
||||
{
|
||||
child_allocation.x = y;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
else
|
||||
{
|
||||
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
|
||||
child_allocation.x = mirror_point - y - height;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
|
||||
gtk_widget_size_allocate (child, &child_allocation, -1);
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_grid_view_compute_total_height (GtkGridView *self)
|
||||
{
|
||||
@@ -753,8 +747,6 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
||||
int x, y;
|
||||
guint i;
|
||||
|
||||
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (widget));
|
||||
|
||||
orientation = gtk_list_base_get_orientation (GTK_LIST_BASE (self));
|
||||
scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), orientation);
|
||||
opposite_orientation = OPPOSITE_ORIENTATION (orientation);
|
||||
@@ -873,7 +865,7 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
||||
{
|
||||
row_height += cell->size;
|
||||
|
||||
gtk_grid_view_size_allocate_child (self,
|
||||
gtk_list_base_size_allocate_child (GTK_LIST_BASE (self),
|
||||
cell->parent.widget,
|
||||
x + ceil (self->column_width * i),
|
||||
y,
|
||||
@@ -914,6 +906,8 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (widget));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1037,6 +1031,7 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
|
||||
list_base_class->list_item_augment_func = cell_augment;
|
||||
list_base_class->get_allocation_along = gtk_grid_view_get_allocation_along;
|
||||
list_base_class->get_allocation_across = gtk_grid_view_get_allocation_across;
|
||||
list_base_class->get_items_in_rect = gtk_grid_view_get_items_in_rect;
|
||||
list_base_class->get_position_from_allocation = gtk_grid_view_get_position_from_allocation;
|
||||
list_base_class->move_focus_along = gtk_grid_view_move_focus_along;
|
||||
list_base_class->move_focus_across = gtk_grid_view_move_focus_across;
|
||||
|
||||
+29
-25
@@ -55,6 +55,13 @@
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
#define GTK_VECTOR_ELEMENT_TYPE char *
|
||||
#define GTK_VECTOR_NULL_TERMINATED 1
|
||||
#define GTK_VECTOR_FREE_FUNC g_free
|
||||
#define GTK_VECTOR_TYPE_NAME GtkStrvBuilder
|
||||
#define GTK_VECTOR_NAME gtk_strv_builder
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkicontheme
|
||||
* @Short_description: Looking up icons by name
|
||||
@@ -2276,13 +2283,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 +2303,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 +2334,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
|
||||
{
|
||||
|
||||
@@ -93,6 +93,8 @@ struct _GtkIMContextWayland
|
||||
guint use_preedit : 1;
|
||||
};
|
||||
|
||||
static void gtk_im_context_wayland_focus_out (GtkIMContext *context);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkIMContextWayland, gtk_im_context_wayland, GTK_TYPE_IM_CONTEXT_SIMPLE,
|
||||
gtk_im_module_ensure_extension_point ();
|
||||
g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME,
|
||||
@@ -476,6 +478,8 @@ gtk_im_context_wayland_finalize (GObject *object)
|
||||
{
|
||||
GtkIMContextWayland *context = GTK_IM_CONTEXT_WAYLAND (object);
|
||||
|
||||
gtk_im_context_wayland_focus_out (GTK_IM_CONTEXT (context));
|
||||
|
||||
g_clear_object (&context->widget);
|
||||
g_clear_object (&context->gesture);
|
||||
g_free (context->surrounding.text);
|
||||
|
||||
+302
-134
@@ -22,6 +22,8 @@
|
||||
#include "gtklistbaseprivate.h"
|
||||
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkdropcontrollermotion.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgizmoprivate.h"
|
||||
@@ -30,7 +32,6 @@
|
||||
#include "gtkmultiselection.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkscrollable.h"
|
||||
#include "gtkset.h"
|
||||
#include "gtksingleselection.h"
|
||||
#include "gtksnapshot.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
@@ -41,24 +42,15 @@ typedef struct _RubberbandData RubberbandData;
|
||||
|
||||
struct _RubberbandData
|
||||
{
|
||||
GtkWidget *widget;
|
||||
GtkSet *active;
|
||||
double x1, y1;
|
||||
double x2, y2;
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
GtkWidget *widget; /* The rubberband widget */
|
||||
|
||||
GtkListItemTracker *start_tracker; /* The item we started dragging on */
|
||||
double start_align_across; /* alignment in horizontal direction */
|
||||
double start_align_along; /* alignment in vertical direction */
|
||||
|
||||
double pointer_x, pointer_y; /* mouse coordinates in widget space */
|
||||
};
|
||||
|
||||
static void
|
||||
rubberband_data_free (gpointer data)
|
||||
{
|
||||
RubberbandData *rdata = data;
|
||||
|
||||
g_clear_pointer (&rdata->widget, gtk_widget_unparent);
|
||||
g_clear_pointer (&rdata->active, gtk_set_free);
|
||||
g_free (rdata);
|
||||
}
|
||||
|
||||
typedef struct _GtkListBasePrivate GtkListBasePrivate;
|
||||
|
||||
struct _GtkListBasePrivate
|
||||
@@ -1241,8 +1233,6 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
|
||||
}
|
||||
|
||||
static void gtk_list_base_update_rubberband_selection (GtkListBase *self);
|
||||
|
||||
static gboolean
|
||||
autoscroll_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
@@ -1263,15 +1253,6 @@ autoscroll_cb (GtkWidget *widget,
|
||||
|
||||
delta_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]) - value;
|
||||
|
||||
if (priv->rubberband)
|
||||
{
|
||||
priv->rubberband->x2 += delta_x;
|
||||
priv->rubberband->y2 += delta_y;
|
||||
gtk_list_base_update_rubberband_selection (self);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
if (delta_x != 0 || delta_y != 0)
|
||||
{
|
||||
return G_SOURCE_CONTINUE;
|
||||
@@ -1290,8 +1271,14 @@ add_autoscroll (GtkListBase *self,
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
priv->autoscroll_delta_x = delta_x;
|
||||
priv->autoscroll_delta_y = delta_y;
|
||||
if (gtk_list_base_adjustment_is_flipped (self, GTK_ORIENTATION_HORIZONTAL))
|
||||
priv->autoscroll_delta_x = -delta_x;
|
||||
else
|
||||
priv->autoscroll_delta_x = delta_x;
|
||||
if (gtk_list_base_adjustment_is_flipped (self, GTK_ORIENTATION_VERTICAL))
|
||||
priv->autoscroll_delta_y = -delta_y;
|
||||
else
|
||||
priv->autoscroll_delta_y = delta_y;
|
||||
|
||||
if (priv->autoscroll_id == 0)
|
||||
priv->autoscroll_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), autoscroll_cb, self, NULL);
|
||||
@@ -1346,76 +1333,214 @@ update_autoscroll (GtkListBase *self,
|
||||
remove_autoscroll (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_base_size_allocate_child:
|
||||
* @self: The listbase
|
||||
* @child: The child
|
||||
* @x: top left coordinate in the across direction
|
||||
* @y: top right coordinate in the along direction
|
||||
* @width: size in the across direction
|
||||
* @height: size in the along direction
|
||||
*
|
||||
* Allocates a child widget in the list coordinate system,
|
||||
* but with the coordinates already offset by the scroll
|
||||
* offset.
|
||||
**/
|
||||
void
|
||||
gtk_list_base_size_allocate_child (GtkListBase *self,
|
||||
GtkWidget *child,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkAllocation child_allocation;
|
||||
|
||||
if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
if (_gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
||||
{
|
||||
child_allocation.x = x;
|
||||
child_allocation.y = y;
|
||||
child_allocation.width = width;
|
||||
child_allocation.height = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
|
||||
child_allocation.x = mirror_point - x - width;
|
||||
child_allocation.y = y;
|
||||
child_allocation.width = width;
|
||||
child_allocation.height = height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
||||
{
|
||||
child_allocation.x = y;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
else
|
||||
{
|
||||
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
|
||||
child_allocation.x = mirror_point - y - height;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_widget_size_allocate (child, &child_allocation, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_widget_to_list (GtkListBase *self,
|
||||
double x_widget,
|
||||
double y_widget,
|
||||
int *across_out,
|
||||
int *along_out)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
||||
x_widget = gtk_widget_get_width (widget) - x_widget;
|
||||
|
||||
gtk_list_base_get_adjustment_values (self, OPPOSITE_ORIENTATION (priv->orientation), across_out, NULL, NULL);
|
||||
gtk_list_base_get_adjustment_values (self, priv->orientation, along_out, NULL, NULL);
|
||||
|
||||
if (priv->orientation == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
*across_out += x_widget;
|
||||
*along_out += y_widget;
|
||||
}
|
||||
else
|
||||
{
|
||||
*across_out += y_widget;
|
||||
*along_out += x_widget;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkBitset *
|
||||
gtk_list_base_get_items_in_rect (GtkListBase *self,
|
||||
const GdkRectangle *rect)
|
||||
{
|
||||
return GTK_LIST_BASE_GET_CLASS (self)->get_items_in_rect (self, rect);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_base_get_rubberband_coords (GtkListBase *self,
|
||||
GdkRectangle *rect)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
int x1, x2, y1, y2;
|
||||
|
||||
if (!priv->rubberband)
|
||||
return FALSE;
|
||||
|
||||
if (priv->rubberband->start_tracker == NULL)
|
||||
{
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
guint pos = gtk_list_item_tracker_get_position (priv->item_manager, priv->rubberband->start_tracker);
|
||||
|
||||
if (gtk_list_base_get_allocation_along (self, pos, &y1, &y2) &&
|
||||
gtk_list_base_get_allocation_across (self, pos, &x1, &x2))
|
||||
{
|
||||
x1 += x2 * priv->rubberband->start_align_across;
|
||||
y1 += y2 * priv->rubberband->start_align_along;
|
||||
}
|
||||
else
|
||||
{
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_list_base_widget_to_list (self,
|
||||
priv->rubberband->pointer_x, priv->rubberband->pointer_y,
|
||||
&x2, &y2);
|
||||
|
||||
rect->x = MIN (x1, x2);
|
||||
rect->y = MIN (y1, y2);
|
||||
rect->width = ABS (x1 - x2) + 1;
|
||||
rect->height = ABS (y1 - y2) + 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_base_allocate_rubberband (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkRequisition min_size;
|
||||
GdkRectangle rect;
|
||||
double x, y;
|
||||
int min, nat;
|
||||
int offset_x, offset_y;
|
||||
|
||||
if (!priv->rubberband)
|
||||
if (!gtk_list_base_get_rubberband_coords (self, &rect))
|
||||
return;
|
||||
|
||||
gtk_widget_measure (priv->rubberband->widget,
|
||||
GTK_ORIENTATION_HORIZONTAL, -1,
|
||||
&min, &nat, NULL, NULL);
|
||||
gtk_widget_get_preferred_size (priv->rubberband->widget, &min_size, NULL);
|
||||
rect.width = MAX (min_size.width, rect.width);
|
||||
rect.height = MAX (min_size.height, rect.height);
|
||||
|
||||
x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
gtk_list_base_get_adjustment_values (self, OPPOSITE_ORIENTATION (priv->orientation), &offset_x, NULL, NULL);
|
||||
gtk_list_base_get_adjustment_values (self, priv->orientation, &offset_y, NULL, NULL);
|
||||
rect.x -= offset_x;
|
||||
rect.y -= offset_y;
|
||||
|
||||
rect.x = MIN (priv->rubberband->x1, priv->rubberband->x2) - x;
|
||||
rect.y = MIN (priv->rubberband->y1, priv->rubberband->y2) - y;
|
||||
rect.width = ABS (priv->rubberband->x1 - priv->rubberband->x2) + 1;
|
||||
rect.height = ABS (priv->rubberband->y1 - priv->rubberband->y2) + 1;
|
||||
|
||||
gtk_widget_size_allocate (priv->rubberband->widget, &rect, -1);
|
||||
gtk_list_base_size_allocate_child (self,
|
||||
priv->rubberband->widget,
|
||||
rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_start_rubberband (GtkListBase *self,
|
||||
double x,
|
||||
double y,
|
||||
gboolean modify,
|
||||
gboolean extend)
|
||||
double y)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
double value_x, value_y;
|
||||
cairo_rectangle_int_t item_area;
|
||||
int list_x, list_y;
|
||||
guint pos;
|
||||
|
||||
if (priv->rubberband)
|
||||
return;
|
||||
|
||||
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
gtk_list_base_widget_to_list (self, x, y, &list_x, &list_y);
|
||||
if (!gtk_list_base_get_position_from_allocation (self, list_x, list_y, &pos, &item_area))
|
||||
{
|
||||
g_warning ("Could not start rubberbanding: No item\n");
|
||||
return;
|
||||
}
|
||||
|
||||
priv->rubberband = g_new0 (RubberbandData, 1);
|
||||
|
||||
priv->rubberband->x1 = priv->rubberband->x2 = x + value_x;
|
||||
priv->rubberband->y1 = priv->rubberband->y2 = y + value_y;
|
||||
priv->rubberband->start_tracker = gtk_list_item_tracker_new (priv->item_manager);
|
||||
gtk_list_item_tracker_set_position (priv->item_manager, priv->rubberband->start_tracker, pos, 0, 0);
|
||||
priv->rubberband->start_align_across = (double) (list_x - item_area.x) / item_area.width;
|
||||
priv->rubberband->start_align_along = (double) (list_y - item_area.y) / item_area.height;
|
||||
|
||||
priv->rubberband->modify = modify;
|
||||
priv->rubberband->extend = extend;
|
||||
priv->rubberband->pointer_x = x;
|
||||
priv->rubberband->pointer_y = y;
|
||||
|
||||
priv->rubberband->widget = gtk_gizmo_new ("rubberband",
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
gtk_widget_set_parent (priv->rubberband->widget, GTK_WIDGET (self));
|
||||
priv->rubberband->active = gtk_set_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
range_cb (guint position,
|
||||
guint *start,
|
||||
guint *n_items,
|
||||
gboolean *selected,
|
||||
gpointer data)
|
||||
{
|
||||
GtkSet *set = data;
|
||||
|
||||
gtk_set_find_range (set, position, gtk_set_get_max (set) + 1, start, n_items, selected);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_stop_rubberband (GtkListBase *self)
|
||||
gtk_list_base_stop_rubberband (GtkListBase *self,
|
||||
gboolean modify,
|
||||
gboolean extend)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkListItemManagerItem *item;
|
||||
@@ -1433,22 +1558,102 @@ gtk_list_base_stop_rubberband (GtkListBase *self)
|
||||
}
|
||||
|
||||
model = gtk_list_item_manager_get_model (priv->item_manager);
|
||||
if (model != NULL)
|
||||
{
|
||||
GtkBitset *selected, *mask;
|
||||
GdkRectangle rect;
|
||||
GtkBitset *rubberband_selection;
|
||||
|
||||
if (priv->rubberband->modify)
|
||||
{
|
||||
gtk_selection_model_unselect_callback (model, range_cb, priv->rubberband->active);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_selection_model_select_callback (model,
|
||||
!priv->rubberband->extend,
|
||||
range_cb, priv->rubberband->active);
|
||||
if (!gtk_list_base_get_rubberband_coords (self, &rect))
|
||||
return;
|
||||
|
||||
rubberband_selection = gtk_list_base_get_items_in_rect (self, &rect);
|
||||
if (gtk_bitset_is_empty (rubberband_selection))
|
||||
{
|
||||
gtk_bitset_unref (rubberband_selection);
|
||||
return;
|
||||
}
|
||||
|
||||
if (modify && extend) /* Ctrl + Shift */
|
||||
{
|
||||
GtkBitset *current;
|
||||
guint min = gtk_bitset_get_minimum (rubberband_selection);
|
||||
guint max = gtk_bitset_get_maximum (rubberband_selection);
|
||||
/* toggle the rubberband, keep the rest */
|
||||
current = gtk_selection_model_get_selection_in_range (model, min, max - min + 1);
|
||||
selected = gtk_bitset_copy (current);
|
||||
gtk_bitset_unref (current);
|
||||
gtk_bitset_intersect (selected, rubberband_selection);
|
||||
gtk_bitset_difference (selected, rubberband_selection);
|
||||
|
||||
mask = gtk_bitset_ref (rubberband_selection);
|
||||
}
|
||||
else if (modify) /* Ctrl */
|
||||
{
|
||||
/* select the rubberband, keep the rest */
|
||||
selected = gtk_bitset_ref (rubberband_selection);
|
||||
mask = gtk_bitset_ref (rubberband_selection);
|
||||
}
|
||||
else if (extend) /* Shift */
|
||||
{
|
||||
/* unselect the rubberband, keep the rest */
|
||||
selected = gtk_bitset_new_empty ();
|
||||
mask = gtk_bitset_ref (rubberband_selection);
|
||||
}
|
||||
else /* no modifer */
|
||||
{
|
||||
/* select the rubberband, clear the rest */
|
||||
selected = gtk_bitset_ref (rubberband_selection);
|
||||
mask = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add_range (mask, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
|
||||
gtk_selection_model_set_selection (model, selected, mask);
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
gtk_bitset_unref (mask);
|
||||
gtk_bitset_unref (rubberband_selection);
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->rubberband, rubberband_data_free);
|
||||
gtk_list_item_tracker_free (priv->item_manager, priv->rubberband->start_tracker);
|
||||
g_clear_pointer (&priv->rubberband->widget, gtk_widget_unparent);
|
||||
g_free (priv->rubberband);
|
||||
priv->rubberband = NULL;
|
||||
|
||||
remove_autoscroll (self);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
static void
|
||||
gtk_list_base_update_rubberband_selection (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkListItemManagerItem *item;
|
||||
GdkRectangle rect;
|
||||
guint pos;
|
||||
GtkBitset *rubberband_selection;
|
||||
|
||||
if (!gtk_list_base_get_rubberband_coords (self, &rect))
|
||||
return;
|
||||
|
||||
rubberband_selection = gtk_list_base_get_items_in_rect (self, &rect);
|
||||
|
||||
pos = 0;
|
||||
for (item = gtk_list_item_manager_get_first (priv->item_manager);
|
||||
item != NULL;
|
||||
item = gtk_rb_tree_node_get_next (item))
|
||||
{
|
||||
if (item->widget)
|
||||
{
|
||||
if (gtk_bitset_contains (rubberband_selection, pos))
|
||||
gtk_widget_set_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE, FALSE);
|
||||
else
|
||||
gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
|
||||
pos += item->n_items;
|
||||
}
|
||||
|
||||
gtk_bitset_unref (rubberband_selection);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1461,51 +1666,14 @@ gtk_list_base_update_rubberband (GtkListBase *self,
|
||||
if (!priv->rubberband)
|
||||
return;
|
||||
|
||||
priv->rubberband->x2 = x + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
priv->rubberband->y2 = y + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
priv->rubberband->pointer_x = x;
|
||||
priv->rubberband->pointer_y = y;
|
||||
|
||||
gtk_list_base_update_rubberband_selection (self);
|
||||
|
||||
update_autoscroll (self, x, y);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_update_rubberband_selection (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GdkRectangle rect;
|
||||
GdkRectangle alloc;
|
||||
GtkListItemManagerItem *item;
|
||||
|
||||
gtk_list_base_allocate_rubberband (self);
|
||||
gtk_widget_get_allocation (priv->rubberband->widget, &rect);
|
||||
|
||||
for (item = gtk_list_item_manager_get_first (priv->item_manager);
|
||||
item != NULL;
|
||||
item = gtk_rb_tree_node_get_next (item))
|
||||
{
|
||||
guint pos;
|
||||
|
||||
if (!item->widget)
|
||||
continue;
|
||||
|
||||
pos = gtk_list_item_manager_get_item_position (priv->item_manager, item);
|
||||
|
||||
gtk_widget_get_allocation (item->widget, &alloc);
|
||||
|
||||
if (gdk_rectangle_intersect (&rect, &alloc, &alloc))
|
||||
{
|
||||
gtk_set_add_item (priv->rubberband->active, pos);
|
||||
gtk_widget_set_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_set_remove_item (priv->rubberband->active, pos);
|
||||
gtk_widget_unset_state_flags (item->widget, GTK_STATE_FLAG_ACTIVE);
|
||||
}
|
||||
}
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1529,27 +1697,25 @@ get_selection_modifiers (GtkGesture *gesture,
|
||||
*extend = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_drag_begin (GtkGestureDrag *gesture,
|
||||
double start_x,
|
||||
double start_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
|
||||
get_selection_modifiers (GTK_GESTURE (gesture), &modify, &extend);
|
||||
gtk_list_base_start_rubberband (self, start_x, start_y, modify, extend);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_drag_update (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
double start_x, start_y;
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
|
||||
if (!priv->rubberband)
|
||||
{
|
||||
if (!gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, offset_y))
|
||||
return;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
gtk_list_base_start_rubberband (self, start_x, start_y);
|
||||
}
|
||||
gtk_list_base_update_rubberband (self, start_x + offset_x, start_y + offset_y);
|
||||
}
|
||||
|
||||
@@ -1559,8 +1725,11 @@ gtk_list_base_drag_end (GtkGestureDrag *gesture,
|
||||
double offset_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
gboolean modify, extend;
|
||||
|
||||
gtk_list_base_drag_update (gesture, offset_x, offset_y, self);
|
||||
gtk_list_base_stop_rubberband (self);
|
||||
get_selection_modifiers (GTK_GESTURE (gesture), &modify, &extend);
|
||||
gtk_list_base_stop_rubberband (self, modify, extend);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1577,7 +1746,6 @@ gtk_list_base_set_enable_rubberband (GtkListBase *self,
|
||||
if (enable)
|
||||
{
|
||||
priv->drag_gesture = gtk_gesture_drag_new ();
|
||||
g_signal_connect (priv->drag_gesture, "drag-begin", G_CALLBACK (gtk_list_base_drag_begin), self);
|
||||
g_signal_connect (priv->drag_gesture, "drag-update", G_CALLBACK (gtk_list_base_drag_update), self);
|
||||
g_signal_connect (priv->drag_gesture, "drag-end", G_CALLBACK (gtk_list_base_drag_end), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (priv->drag_gesture));
|
||||
|
||||
@@ -54,6 +54,8 @@ struct _GtkListBaseClass
|
||||
int along,
|
||||
guint *pos,
|
||||
cairo_rectangle_int_t *area);
|
||||
GtkBitset * (* get_items_in_rect) (GtkListBase *self,
|
||||
const cairo_rectangle_int_t *rect);
|
||||
guint (* move_focus_along) (GtkListBase *self,
|
||||
guint pos,
|
||||
int steps);
|
||||
@@ -99,10 +101,17 @@ gboolean gtk_list_base_grab_focus_on_item (GtkListBase
|
||||
gboolean select,
|
||||
gboolean modify,
|
||||
gboolean extend);
|
||||
|
||||
void gtk_list_base_set_enable_rubberband (GtkListBase *self,
|
||||
gboolean enable);
|
||||
gboolean gtk_list_base_get_enable_rubberband (GtkListBase *self);
|
||||
|
||||
void gtk_list_base_allocate_rubberband (GtkListBase *self);
|
||||
|
||||
void gtk_list_base_size_allocate_child (GtkListBase *self,
|
||||
GtkWidget *child,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
#endif /* __GTK_LIST_BASE_PRIVATE_H__ */
|
||||
|
||||
+3
-3
@@ -332,7 +332,7 @@ gtk_list_item_set_child (GtkListItem *self,
|
||||
* @self: a #GtkListItem
|
||||
*
|
||||
* Gets the position in the model that @self currently displays.
|
||||
* If @self is unbound, 0 is returned.
|
||||
* If @self is unbound, %GTK_INVALID_LIST_POSITION is returned.
|
||||
*
|
||||
* Returns: The position of this item
|
||||
**/
|
||||
@@ -443,10 +443,10 @@ gtk_list_item_get_activatable (GtkListItem *self)
|
||||
* Sets @self to be activatable.
|
||||
*
|
||||
* If an item is activatable, double-clicking on the item, using
|
||||
* the <Return> key or calling gtk_widget_activate() will activate
|
||||
* the Return key or calling gtk_widget_activate() will activate
|
||||
* the item. Activating instructs the containing view to handle
|
||||
* activation. #GtkListView for example will be emitting the
|
||||
* GtkListView::activate signal.
|
||||
* #GtkListView::activate signal.
|
||||
*
|
||||
* By default, list items are activatable
|
||||
**/
|
||||
|
||||
@@ -88,10 +88,10 @@ GtkSelectionModel * gtk_list_item_manager_get_model (GtkListItemMana
|
||||
|
||||
guint gtk_list_item_manager_get_size (GtkListItemManager *self);
|
||||
void gtk_list_item_manager_set_single_click_activate
|
||||
(GtkListItemManager *self,
|
||||
gboolean single_click_activate);
|
||||
(GtkListItemManager *self,
|
||||
gboolean single_click_activate);
|
||||
gboolean gtk_list_item_manager_get_single_click_activate
|
||||
(GtkListItemManager *self);
|
||||
(GtkListItemManager *self);
|
||||
|
||||
GtkListItemTracker * gtk_list_item_tracker_new (GtkListItemManager *self);
|
||||
void gtk_list_item_tracker_free (GtkListItemManager *self,
|
||||
|
||||
+35
-40
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gtklistview.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistbaseprivate.h"
|
||||
#include "gtklistitemmanagerprivate.h"
|
||||
@@ -374,6 +375,36 @@ gtk_list_view_get_allocation_across (GtkListBase *base,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GtkBitset *
|
||||
gtk_list_view_get_items_in_rect (GtkListBase *base,
|
||||
const cairo_rectangle_int_t *rect)
|
||||
{
|
||||
GtkListView *self = GTK_LIST_VIEW (base);
|
||||
guint first, last, n_items;
|
||||
GtkBitset *result;
|
||||
ListRow *row;
|
||||
|
||||
result = gtk_bitset_new_empty ();
|
||||
|
||||
n_items = gtk_list_base_get_n_items (base);
|
||||
if (n_items == 0)
|
||||
return result;
|
||||
|
||||
row = gtk_list_view_get_row_at_y (self, rect->y, NULL);
|
||||
if (row)
|
||||
first = gtk_list_item_manager_get_item_position (self->item_manager, row);
|
||||
else
|
||||
first = rect->y < 0 ? 0 : n_items - 1;
|
||||
row = gtk_list_view_get_row_at_y (self, rect->y + rect->height, NULL);
|
||||
if (row)
|
||||
last = gtk_list_item_manager_get_item_position (self->item_manager, row);
|
||||
else
|
||||
last = rect->y < 0 ? 0 : n_items - 1;
|
||||
|
||||
gtk_bitset_add_range_closed (result, first, last);
|
||||
return result;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_list_view_move_focus_along (GtkListBase *base,
|
||||
guint pos,
|
||||
@@ -553,43 +584,6 @@ gtk_list_view_measure (GtkWidget *widget,
|
||||
gtk_list_view_measure_across (widget, orientation, for_size, minimum, natural);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_size_allocate_child (GtkListView *self,
|
||||
GtkWidget *child,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
GtkAllocation child_allocation;
|
||||
|
||||
if (gtk_list_base_get_orientation (GTK_LIST_BASE (self)) == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
child_allocation.x = x;
|
||||
child_allocation.y = y;
|
||||
child_allocation.width = width;
|
||||
child_allocation.height = height;
|
||||
}
|
||||
else if (_gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_LTR)
|
||||
{
|
||||
child_allocation.x = y;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
else
|
||||
{
|
||||
int mirror_point = gtk_widget_get_width (GTK_WIDGET (self));
|
||||
|
||||
child_allocation.x = mirror_point - y - height;
|
||||
child_allocation.y = x;
|
||||
child_allocation.width = height;
|
||||
child_allocation.height = width;
|
||||
}
|
||||
|
||||
gtk_widget_size_allocate (child, &child_allocation, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_view_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
@@ -604,8 +598,6 @@ gtk_list_view_size_allocate (GtkWidget *widget,
|
||||
GtkOrientation orientation, opposite_orientation;
|
||||
GtkScrollablePolicy scroll_policy;
|
||||
|
||||
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (self));
|
||||
|
||||
orientation = gtk_list_base_get_orientation (GTK_LIST_BASE (self));
|
||||
opposite_orientation = OPPOSITE_ORIENTATION (orientation);
|
||||
scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), orientation);
|
||||
@@ -685,7 +677,7 @@ gtk_list_view_size_allocate (GtkWidget *widget,
|
||||
{
|
||||
if (row->parent.widget)
|
||||
{
|
||||
gtk_list_view_size_allocate_child (self,
|
||||
gtk_list_base_size_allocate_child (GTK_LIST_BASE (self),
|
||||
row->parent.widget,
|
||||
x,
|
||||
y,
|
||||
@@ -695,6 +687,8 @@ gtk_list_view_size_allocate (GtkWidget *widget,
|
||||
|
||||
y += row->height * row->parent.n_items;
|
||||
}
|
||||
|
||||
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -810,6 +804,7 @@ gtk_list_view_class_init (GtkListViewClass *klass)
|
||||
list_base_class->list_item_augment_func = list_row_augment;
|
||||
list_base_class->get_allocation_along = gtk_list_view_get_allocation_along;
|
||||
list_base_class->get_allocation_across = gtk_list_view_get_allocation_across;
|
||||
list_base_class->get_items_in_rect = gtk_list_view_get_items_in_rect;
|
||||
list_base_class->get_position_from_allocation = gtk_list_view_get_position_from_allocation;
|
||||
list_base_class->move_focus_along = gtk_list_view_move_focus_along;
|
||||
list_base_class->move_focus_across = gtk_list_view_move_focus_across;
|
||||
|
||||
+50
-49
@@ -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;
|
||||
@@ -159,25 +165,25 @@ DisplayDebugFlags debug_flags[N_DEBUG_DISPLAYS];
|
||||
gboolean any_display_debug_flags_set = FALSE;
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
static const GDebugKey gtk_debug_keys[] = {
|
||||
{ "text", GTK_DEBUG_TEXT },
|
||||
{ "tree", GTK_DEBUG_TREE },
|
||||
{ "keybindings", GTK_DEBUG_KEYBINDINGS },
|
||||
{ "modules", GTK_DEBUG_MODULES },
|
||||
{ "geometry", GTK_DEBUG_GEOMETRY },
|
||||
{ "icontheme", GTK_DEBUG_ICONTHEME },
|
||||
{ "printing", GTK_DEBUG_PRINTING} ,
|
||||
{ "builder", GTK_DEBUG_BUILDER },
|
||||
{ "size-request", GTK_DEBUG_SIZE_REQUEST },
|
||||
{ "no-css-cache", GTK_DEBUG_NO_CSS_CACHE },
|
||||
{ "shortcuts", GTK_DEBUG_SHORTCUTS },
|
||||
{ "interactive", GTK_DEBUG_INTERACTIVE },
|
||||
{ "touchscreen", GTK_DEBUG_TOUCHSCREEN },
|
||||
{ "actions", GTK_DEBUG_ACTIONS },
|
||||
{ "resize", GTK_DEBUG_RESIZE },
|
||||
{ "layout", GTK_DEBUG_LAYOUT },
|
||||
{ "snapshot", GTK_DEBUG_SNAPSHOT },
|
||||
{ "constraints", GTK_DEBUG_CONSTRAINTS },
|
||||
static const GdkDebugKey gtk_debug_keys[] = {
|
||||
{ "keybindings", GTK_DEBUG_KEYBINDINGS, "Information about keyboard shortcuts" },
|
||||
{ "modules", GTK_DEBUG_MODULES, "Information about modules and extensions" },
|
||||
{ "icontheme", GTK_DEBUG_ICONTHEME, "Information about icon themes" },
|
||||
{ "printing", GTK_DEBUG_PRINTING, "Information about printing" },
|
||||
{ "geometry", GTK_DEBUG_GEOMETRY, "Information about size allocation" },
|
||||
{ "size-request", GTK_DEBUG_SIZE_REQUEST, "Information about size requests" },
|
||||
{ "actions", GTK_DEBUG_ACTIONS, "Information about actions and menu models" },
|
||||
{ "constraints", GTK_DEBUG_CONSTRAINTS, "Information about constraints" },
|
||||
{ "text", GTK_DEBUG_TEXT, "Information about GtkTextView" },
|
||||
{ "tree", GTK_DEBUG_TREE, "Information about GtkTreeView" },
|
||||
{ "builder", GTK_DEBUG_BUILDER, "Trace GtkBuilder operation" },
|
||||
{ "builder-objects", GTK_DEBUG_BUILDER_OBJECTS, "Log unused GtkBuilder objects" },
|
||||
{ "no-css-cache", GTK_DEBUG_NO_CSS_CACHE, "Disable style property cache" },
|
||||
{ "interactive", GTK_DEBUG_INTERACTIVE, "Enable the GTK inspector" },
|
||||
{ "touchscreen", GTK_DEBUG_TOUCHSCREEN, "Pretend the pointer is a touchscreen" },
|
||||
{ "resize", GTK_DEBUG_RESIZE, "Highlight resizing widgets" },
|
||||
{ "layout", GTK_DEBUG_LAYOUT, "Show layout borders" },
|
||||
{ "snapshot", GTK_DEBUG_SNAPSHOT, "Generate debug render nodes" },
|
||||
};
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
|
||||
@@ -602,19 +608,15 @@ do_pre_parse_initialization (void)
|
||||
|
||||
gdk_pre_parse ();
|
||||
|
||||
env_string = g_getenv ("GTK_DEBUG");
|
||||
if (env_string != NULL)
|
||||
{
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
debug_flags[0].flags = g_parse_debug_string (env_string,
|
||||
gtk_debug_keys,
|
||||
G_N_ELEMENTS (gtk_debug_keys));
|
||||
any_display_debug_flags_set = debug_flags[0].flags > 0;
|
||||
debug_flags[0].flags = gdk_parse_debug_var ("GTK_DEBUG",
|
||||
gtk_debug_keys,
|
||||
G_N_ELEMENTS (gtk_debug_keys));
|
||||
any_display_debug_flags_set = debug_flags[0].flags > 0;
|
||||
#else
|
||||
g_warning ("GTK_DEBUG set but ignored because gtk isn't built with G_ENABLE_DEBUG");
|
||||
if (g_getenv ("GTK_DEBUG"))
|
||||
g_warning ("GTK_DEBUG set but ignored because GTK isn't built with G_ENABLE_DEBUG");
|
||||
#endif /* G_ENABLE_DEBUG */
|
||||
env_string = NULL;
|
||||
}
|
||||
|
||||
env_string = g_getenv ("GTK_SLOWDOWN");
|
||||
if (env_string)
|
||||
@@ -1325,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)
|
||||
@@ -1380,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;
|
||||
|
||||
@@ -1421,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 *
|
||||
@@ -1753,6 +1754,7 @@ gtk_main_do_event (GdkEvent *event)
|
||||
((gtk_widget_is_sensitive (target_widget) || gdk_event_get_event_type (event) == GDK_SCROLL) &&
|
||||
gtk_widget_is_ancestor (target_widget, grab_widget)) ||
|
||||
(GTK_IS_WINDOW (grab_widget) &&
|
||||
GTK_IS_WINDOW (event_widget) &&
|
||||
grab_widget != event_widget &&
|
||||
is_transient_for (GTK_WINDOW (event_widget), GTK_WINDOW (grab_widget))))
|
||||
grab_widget = target_widget;
|
||||
@@ -1997,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 (;;)
|
||||
{
|
||||
@@ -2011,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))
|
||||
{
|
||||
@@ -2053,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,
|
||||
@@ -2074,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;
|
||||
}
|
||||
|
||||
|
||||
+136
-159
@@ -21,24 +21,18 @@
|
||||
|
||||
#include "gtkmultiselection.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
#include "gtkset.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkmultiselection
|
||||
* @Short_description: A selection model that allows selecting a multiple items
|
||||
* @Short_description: A selection model that allows selecting multiple items
|
||||
* @Title: GtkMultiSelection
|
||||
* @see_also: #GtkSelectionModel
|
||||
*
|
||||
* GtkMultiSelection is an implementation of the #GtkSelectionModel interface
|
||||
* that allows selecting multiple elements.
|
||||
*
|
||||
* Note that due to the way the selection is stored, newly added items are
|
||||
* always unselected, even if they were just removed from the model, and were
|
||||
* selected before. In particular this means that changing the sort order of
|
||||
* an underlying sort model will clear the selection. In other words, the
|
||||
* selection is *not persistent*.
|
||||
*/
|
||||
|
||||
struct _GtkMultiSelection
|
||||
@@ -47,7 +41,8 @@ struct _GtkMultiSelection
|
||||
|
||||
GListModel *model;
|
||||
|
||||
GtkSet *selected;
|
||||
GtkBitset *selected;
|
||||
GHashTable *items; /* item => position */
|
||||
};
|
||||
|
||||
struct _GtkMultiSelectionClass
|
||||
@@ -103,175 +98,106 @@ gtk_multi_selection_is_selected (GtkSelectionModel *model,
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
|
||||
return gtk_set_contains (self->selected, position);
|
||||
return gtk_bitset_contains (self->selected, position);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items,
|
||||
gboolean exclusive)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
guint min = G_MAXUINT;
|
||||
guint max = 0;
|
||||
|
||||
if (exclusive)
|
||||
{
|
||||
min = gtk_set_get_min (self->selected);
|
||||
max = gtk_set_get_max (self->selected);
|
||||
gtk_set_remove_all (self->selected);
|
||||
}
|
||||
|
||||
gtk_set_add_range (self->selected, position, n_items);
|
||||
|
||||
min = MIN (position, min);
|
||||
max = MAX (max, position + n_items - 1);
|
||||
|
||||
gtk_selection_model_selection_changed (model, min, max - min + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
static GtkBitset *
|
||||
gtk_multi_selection_get_selection_in_range (GtkSelectionModel *model,
|
||||
guint pos,
|
||||
guint n_items)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
|
||||
gtk_set_remove_range (self->selected, position, n_items);
|
||||
gtk_selection_model_selection_changed (model, position, n_items);
|
||||
|
||||
return TRUE;
|
||||
return gtk_bitset_ref (self->selected);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_item (GtkSelectionModel *model,
|
||||
guint position,
|
||||
gboolean exclusive)
|
||||
static void
|
||||
gtk_multi_selection_toggle_selection (GtkMultiSelection *self,
|
||||
GtkBitset *changes)
|
||||
{
|
||||
return gtk_multi_selection_select_range (model, position, 1, exclusive);
|
||||
}
|
||||
GListModel *model = G_LIST_MODEL (self);
|
||||
GtkBitsetIter change_iter, selected_iter;
|
||||
GtkBitset *selected;
|
||||
guint change_pos, selected_pos;
|
||||
gboolean more;
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_item (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return gtk_multi_selection_unselect_range (model, position, 1);
|
||||
}
|
||||
gtk_bitset_difference (self->selected, changes);
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_all (GtkSelectionModel *model)
|
||||
{
|
||||
return gtk_multi_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE);
|
||||
}
|
||||
selected = gtk_bitset_copy (changes);
|
||||
gtk_bitset_intersect (selected, self->selected);
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_all (GtkSelectionModel *model)
|
||||
{
|
||||
return gtk_multi_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
if (!gtk_bitset_iter_init_first (&selected_iter, selected, &selected_pos))
|
||||
selected_pos = G_MAXUINT;
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_add_or_remove (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
gboolean add,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
guint pos, start, n_items;
|
||||
gboolean in;
|
||||
guint min, max;
|
||||
guint n;
|
||||
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
|
||||
min = G_MAXUINT;
|
||||
max = 0;
|
||||
|
||||
if (unselect_rest)
|
||||
for (more = gtk_bitset_iter_init_first (&change_iter, changes, &change_pos);
|
||||
more;
|
||||
more = gtk_bitset_iter_next (&change_iter, &change_pos))
|
||||
{
|
||||
min = gtk_set_get_min (self->selected);
|
||||
max = gtk_set_get_max (self->selected);
|
||||
gtk_set_remove_all (self->selected);
|
||||
}
|
||||
gpointer item = g_list_model_get_item (model, change_pos);
|
||||
|
||||
for (pos = 0; pos < n; pos = start + n_items)
|
||||
{
|
||||
callback (pos, &start, &n_items, &in, data);
|
||||
|
||||
if (n_items == 0)
|
||||
break;
|
||||
|
||||
g_assert (start <= pos && pos < start + n_items);
|
||||
|
||||
if (in)
|
||||
if (change_pos < selected_pos)
|
||||
{
|
||||
if (start < min)
|
||||
min = start;
|
||||
if (start + n_items - 1 > max)
|
||||
max = start + n_items - 1;
|
||||
|
||||
if (add)
|
||||
gtk_set_add_range (self->selected, start, n_items);
|
||||
else
|
||||
gtk_set_remove_range (self->selected, start, n_items);
|
||||
g_hash_table_remove (self->items, item);
|
||||
g_object_unref (item);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (change_pos == selected_pos);
|
||||
|
||||
pos = start + n_items;
|
||||
g_hash_table_insert (self->items, item, GUINT_TO_POINTER (change_pos));
|
||||
|
||||
if (!gtk_bitset_iter_next (&selected_iter, &selected_pos))
|
||||
selected_pos = G_MAXUINT;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_set_selection (GtkSelectionModel *model,
|
||||
GtkBitset *selected,
|
||||
GtkBitset *mask)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
GtkBitset *changes;
|
||||
guint min, max, n_items;
|
||||
|
||||
/* changes = (self->selected XOR selected) AND mask
|
||||
* But doing it this way avoids looking at all values outside the mask
|
||||
*/
|
||||
changes = gtk_bitset_copy (selected);
|
||||
gtk_bitset_difference (changes, self->selected);
|
||||
gtk_bitset_intersect (changes, mask);
|
||||
|
||||
min = gtk_bitset_get_minimum (changes);
|
||||
max = gtk_bitset_get_maximum (changes);
|
||||
|
||||
/* sanity check */
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
if (max >= n_items)
|
||||
{
|
||||
gtk_bitset_remove_range_closed (changes, n_items, max);
|
||||
max = gtk_bitset_get_maximum (changes);
|
||||
}
|
||||
|
||||
/* actually do the change */
|
||||
gtk_multi_selection_toggle_selection (self, changes);
|
||||
|
||||
gtk_bitset_unref (changes);
|
||||
|
||||
if (min <= max)
|
||||
gtk_selection_model_selection_changed (model, min, max - min + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_callback (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return gtk_multi_selection_add_or_remove (model, unselect_rest, TRUE, callback, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_callback (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return gtk_multi_selection_add_or_remove (model, FALSE, FALSE, callback, data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
guint upper_bound = g_list_model_get_n_items (self->model);
|
||||
|
||||
gtk_set_find_range (self->selected, position, upper_bound, start_range, n_items, selected);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_multi_selection_is_selected;
|
||||
iface->select_item = gtk_multi_selection_select_item;
|
||||
iface->unselect_item = gtk_multi_selection_unselect_item;
|
||||
iface->select_range = gtk_multi_selection_select_range;
|
||||
iface->unselect_range = gtk_multi_selection_unselect_range;
|
||||
iface->select_all = gtk_multi_selection_select_all;
|
||||
iface->unselect_all = gtk_multi_selection_unselect_all;
|
||||
iface->select_callback = gtk_multi_selection_select_callback;
|
||||
iface->unselect_callback = gtk_multi_selection_unselect_callback;
|
||||
iface->query_range = gtk_multi_selection_query_range;
|
||||
iface->get_selection_in_range = gtk_multi_selection_get_selection_in_range;
|
||||
iface->set_selection = gtk_multi_selection_set_selection;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkMultiSelection, gtk_multi_selection, G_TYPE_OBJECT, 0,
|
||||
@@ -287,8 +213,57 @@ gtk_multi_selection_items_changed_cb (GListModel *model,
|
||||
guint added,
|
||||
GtkMultiSelection *self)
|
||||
{
|
||||
gtk_set_remove_range (self->selected, position, removed);
|
||||
gtk_set_shift (self->selected, position, (int)added - (int)removed);
|
||||
GHashTableIter iter;
|
||||
gpointer item, pos_pointer;
|
||||
GHashTable *pending = NULL;
|
||||
guint i;
|
||||
|
||||
gtk_bitset_slice (self->selected, position, removed, added);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->items);
|
||||
while (g_hash_table_iter_next (&iter, &item, &pos_pointer))
|
||||
{
|
||||
guint pos = GPOINTER_TO_UINT (pos_pointer);
|
||||
|
||||
if (pos < position)
|
||||
continue;
|
||||
else if (pos >= position + removed)
|
||||
g_hash_table_iter_replace (&iter, GUINT_TO_POINTER (pos - removed + added));
|
||||
else /* if pos is in the removed range */
|
||||
{
|
||||
if (added == 0)
|
||||
{
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_iter_steal (&iter);
|
||||
if (pending == NULL)
|
||||
pending = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
|
||||
g_hash_table_add (pending, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = position; pending != NULL && i < position + added; i++)
|
||||
{
|
||||
item = g_list_model_get_item (model, i);
|
||||
if (g_hash_table_contains (pending, item))
|
||||
{
|
||||
gtk_bitset_add (self->selected, i);
|
||||
g_hash_table_insert (self->items, item, GUINT_TO_POINTER (i));
|
||||
g_hash_table_remove (pending, item);
|
||||
if (g_hash_table_size (pending) == 0)
|
||||
g_clear_pointer (&pending, g_hash_table_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_object_unref (item);
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_pointer (&pending, g_hash_table_unref);
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
}
|
||||
|
||||
@@ -306,9 +281,9 @@ gtk_multi_selection_clear_model (GtkMultiSelection *self)
|
||||
|
||||
static void
|
||||
gtk_multi_selection_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
|
||||
@@ -332,9 +307,9 @@ gtk_multi_selection_set_property (GObject *object,
|
||||
|
||||
static void
|
||||
gtk_multi_selection_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
|
||||
|
||||
@@ -357,7 +332,8 @@ gtk_multi_selection_dispose (GObject *object)
|
||||
|
||||
gtk_multi_selection_clear_model (self);
|
||||
|
||||
g_clear_pointer (&self->selected, gtk_set_free);
|
||||
g_clear_pointer (&self->selected, gtk_bitset_unref);
|
||||
g_clear_pointer (&self->items, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_multi_selection_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -389,7 +365,8 @@ gtk_multi_selection_class_init (GtkMultiSelectionClass *klass)
|
||||
static void
|
||||
gtk_multi_selection_init (GtkMultiSelection *self)
|
||||
{
|
||||
self->selected = gtk_set_new ();
|
||||
self->selected = gtk_bitset_new_empty ();
|
||||
self->items = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+8
-13
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gtknoselection.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
|
||||
@@ -96,25 +97,19 @@ gtk_no_selection_is_selected (GtkSelectionModel *model,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_no_selection_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_range,
|
||||
gboolean *selected)
|
||||
static GtkBitset *
|
||||
gtk_no_selection_get_selection_in_range (GtkSelectionModel *model,
|
||||
guint pos,
|
||||
guint n_items)
|
||||
{
|
||||
GtkNoSelection *self = GTK_NO_SELECTION (model);
|
||||
|
||||
*start_range = 0;
|
||||
*n_range = g_list_model_get_n_items (self->model);
|
||||
*selected = FALSE;
|
||||
return gtk_bitset_new_empty ();
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_no_selection_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_no_selection_is_selected;
|
||||
iface->query_range = gtk_no_selection_query_range;
|
||||
iface->is_selected = gtk_no_selection_is_selected;
|
||||
iface->get_selection_in_range = gtk_no_selection_get_selection_in_range;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkNoSelection, gtk_no_selection, G_TYPE_OBJECT, 0,
|
||||
|
||||
@@ -50,6 +50,20 @@
|
||||
*
|
||||
* GtkPasswordEntry provides only minimal API and should be used with the
|
||||
* #GtkEditable API.
|
||||
*
|
||||
* # CSS Nodes
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* entry.password
|
||||
* ╰── text
|
||||
* ├── image.caps-lock-indicator
|
||||
* ┊
|
||||
* ]|
|
||||
*
|
||||
* GtkPasswordEntry has a single CSS node with name entry that carries
|
||||
* a .passwordstyle class. The text Css node below it has a child with
|
||||
* name image and style class .caps-lock-indicator for the Caps Lock
|
||||
* icon, and possibly other children.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
|
||||
+9
-5
@@ -30,7 +30,6 @@
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkstringlist.h"
|
||||
|
||||
/*
|
||||
* SECTION:gtkplacesview
|
||||
@@ -99,7 +98,7 @@ struct _GtkPlacesView
|
||||
GtkSizeGroup *space_size_group;
|
||||
|
||||
GtkEntryCompletion *address_entry_completion;
|
||||
GListModel *completion_store;
|
||||
GtkListStore *completion_store;
|
||||
|
||||
GCancellable *networks_fetching_cancellable;
|
||||
|
||||
@@ -552,12 +551,12 @@ populate_servers (GtkPlacesView *view)
|
||||
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view->recent_servers_listbox))))
|
||||
gtk_list_box_remove (GTK_LIST_BOX (view->listbox), child);
|
||||
|
||||
while (g_list_model_get_n_items (G_LIST_MODEL (view->completion_store)) > 0)
|
||||
gtk_string_list_remove (GTK_STRING_LIST (view->completion_store), 0);
|
||||
gtk_list_store_clear (view->completion_store);
|
||||
|
||||
for (i = 0; i < num_uris; i++)
|
||||
{
|
||||
RemoveServerData *data;
|
||||
GtkTreeIter iter;
|
||||
GtkWidget *row;
|
||||
GtkWidget *grid;
|
||||
GtkWidget *button;
|
||||
@@ -569,7 +568,12 @@ populate_servers (GtkPlacesView *view)
|
||||
dup_uri = g_strdup (uris[i]);
|
||||
|
||||
/* add to the completion list */
|
||||
gtk_string_list_append (GTK_STRING_LIST (view->completion_store), uris[i]);
|
||||
gtk_list_store_append (view->completion_store, &iter);
|
||||
gtk_list_store_set (view->completion_store,
|
||||
&iter,
|
||||
0, name,
|
||||
1, uris[i],
|
||||
-1);
|
||||
|
||||
/* add to the recent servers listbox */
|
||||
row = gtk_list_box_row_new ();
|
||||
|
||||
@@ -1,532 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2020 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkpropertyselection.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkpropertyselection
|
||||
* @Short_description: A selection model that uses an item property
|
||||
* @Title: GtkPropertySelection
|
||||
* @see_also: #GtkSelectionModel
|
||||
*
|
||||
* GtkPropertySelection is an implementation of the #GtkSelectionModel
|
||||
* interface that stores the selected state for each item in a property
|
||||
* of the item.
|
||||
*
|
||||
* The property named by #GtkPropertySelection:property must be writable
|
||||
* boolean property of the item type. GtkPropertySelection preserves the
|
||||
* selected state of items when they are added to the model, but it does
|
||||
* not listen to changes of the property while the item is a part of the
|
||||
* model. It assumes that it has *exclusive* access to the property.
|
||||
*
|
||||
* The advantage of storing the selected state in item properties is that
|
||||
* the state is *persistent* -- when an item is removed and re-added to
|
||||
* the model, it will still have the same selection state. In particular,
|
||||
* this makes the selection persist across changes of the sort order if
|
||||
* the underlying model is a #GtkSortListModel.
|
||||
*/
|
||||
|
||||
struct _GtkPropertySelection
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *model;
|
||||
char *property;
|
||||
};
|
||||
|
||||
struct _GtkPropertySelectionClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODEL,
|
||||
PROP_PROPERTY,
|
||||
|
||||
N_PROPS,
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_property_selection_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_property_selection_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (list);
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_property_selection_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_list_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_property_selection_get_item_type;
|
||||
iface->get_n_items = gtk_property_selection_get_n_items;
|
||||
iface->get_item = gtk_property_selection_get_item;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_selected (GtkPropertySelection *self,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean ret;
|
||||
|
||||
item = g_list_model_get_item (self->model, position);
|
||||
g_object_get (item, self->property, &ret, NULL);
|
||||
g_object_unref (item);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
set_selected (GtkPropertySelection *self,
|
||||
guint position,
|
||||
gboolean selected)
|
||||
{
|
||||
gpointer item;
|
||||
|
||||
item = g_list_model_get_item (self->model, position);
|
||||
g_object_set (item, self->property, selected, NULL);
|
||||
g_object_unref (item);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_is_selected (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return is_selected (GTK_PROPERTY_SELECTION (model), position);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_select_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items,
|
||||
gboolean exclusive)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model);
|
||||
guint i;
|
||||
guint n;
|
||||
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
if (exclusive)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
set_selected (self, i, FALSE);
|
||||
}
|
||||
|
||||
for (i = position; i < position + n_items; i++)
|
||||
set_selected (self, i, TRUE);
|
||||
|
||||
/* FIXME: do better here */
|
||||
if (exclusive)
|
||||
gtk_selection_model_selection_changed (model, 0, n);
|
||||
else
|
||||
gtk_selection_model_selection_changed (model, position, n_items);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_unselect_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model);
|
||||
guint i;
|
||||
|
||||
for (i = position; i < position + n_items; i++)
|
||||
set_selected (self, i, FALSE);
|
||||
|
||||
gtk_selection_model_selection_changed (model, position, n_items);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_select_item (GtkSelectionModel *model,
|
||||
guint position,
|
||||
gboolean exclusive)
|
||||
{
|
||||
return gtk_property_selection_select_range (model, position, 1, exclusive);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_unselect_item (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return gtk_property_selection_unselect_range (model, position, 1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_select_all (GtkSelectionModel *model)
|
||||
{
|
||||
return gtk_property_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_unselect_all (GtkSelectionModel *model)
|
||||
{
|
||||
return gtk_property_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_add_or_remove (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
gboolean add,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model);
|
||||
guint pos, start, n, n_items;
|
||||
gboolean in;
|
||||
guint min, max;
|
||||
guint i;
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
if (unselect_rest)
|
||||
{
|
||||
for (i = 0; i < n_items; i++)
|
||||
set_selected (self, i, FALSE);
|
||||
}
|
||||
|
||||
min = G_MAXUINT;
|
||||
max = 0;
|
||||
|
||||
pos = 0;
|
||||
do
|
||||
{
|
||||
callback (pos, &start, &n, &in, data);
|
||||
if (in)
|
||||
{
|
||||
if (start < min)
|
||||
min = start;
|
||||
if (start + n - 1 > max)
|
||||
max = start + n - 1;
|
||||
|
||||
for (i = start; i < start + n; i++)
|
||||
set_selected (self, i, add);
|
||||
}
|
||||
pos = start + n;
|
||||
}
|
||||
while (n > 0);
|
||||
|
||||
/* FIXME: do better here */
|
||||
if (unselect_rest)
|
||||
gtk_selection_model_selection_changed (model, 0, n_items);
|
||||
else if (min <= max)
|
||||
gtk_selection_model_selection_changed (model, min, max - min + 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_select_callback (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return gtk_property_selection_add_or_remove (model, unselect_rest, TRUE, callback, data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_property_selection_unselect_callback (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return gtk_property_selection_add_or_remove (model, FALSE, FALSE, callback, data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model);
|
||||
guint n;
|
||||
gboolean sel;
|
||||
guint start, end;
|
||||
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||
sel = is_selected (self, position);
|
||||
|
||||
start = position;
|
||||
while (start > 0)
|
||||
{
|
||||
if (is_selected (self, start - 1) != sel)
|
||||
break;
|
||||
start--;
|
||||
}
|
||||
|
||||
end = position;
|
||||
while (end + 1 < n)
|
||||
{
|
||||
if (is_selected (self, end + 1) != sel)
|
||||
break;
|
||||
end++;
|
||||
}
|
||||
|
||||
*start_range = start;
|
||||
*n_items = end - start + 1;
|
||||
*selected = sel;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_property_selection_is_selected;
|
||||
iface->select_item = gtk_property_selection_select_item;
|
||||
iface->unselect_item = gtk_property_selection_unselect_item;
|
||||
iface->select_range = gtk_property_selection_select_range;
|
||||
iface->unselect_range = gtk_property_selection_unselect_range;
|
||||
iface->select_all = gtk_property_selection_select_all;
|
||||
iface->unselect_all = gtk_property_selection_unselect_all;
|
||||
iface->select_callback = gtk_property_selection_select_callback;
|
||||
iface->unselect_callback = gtk_property_selection_unselect_callback;
|
||||
iface->query_range = gtk_property_selection_query_range;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkPropertySelection, gtk_property_selection, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||
gtk_property_selection_list_model_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
|
||||
gtk_property_selection_selection_model_init))
|
||||
|
||||
static void
|
||||
gtk_property_selection_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkPropertySelection *self)
|
||||
{
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_clear_model (GtkPropertySelection *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model,
|
||||
gtk_property_selection_items_changed_cb,
|
||||
self);
|
||||
g_clear_object (&self->model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_real_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (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_property_selection_items_changed_cb),
|
||||
self);
|
||||
break;
|
||||
|
||||
case PROP_PROPERTY:
|
||||
{
|
||||
GObjectClass *class;
|
||||
GParamSpec *prop;
|
||||
|
||||
self->property = g_value_dup_string (value);
|
||||
g_warn_if_fail (self->property != NULL);
|
||||
|
||||
class = g_type_class_ref (g_list_model_get_item_type (self->model));
|
||||
prop = g_object_class_find_property (class, self->property);
|
||||
g_warn_if_fail (prop != NULL &&
|
||||
prop->value_type == G_TYPE_BOOLEAN &&
|
||||
((prop->flags & (G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY)) ==
|
||||
(G_PARAM_READABLE|G_PARAM_WRITABLE)));
|
||||
g_type_class_unref (class);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_real_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, self->model);
|
||||
break;
|
||||
|
||||
case PROP_PROPERTY:
|
||||
g_value_set_string (value, self->property);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_dispose (GObject *object)
|
||||
{
|
||||
GtkPropertySelection *self = GTK_PROPERTY_SELECTION (object);
|
||||
|
||||
gtk_property_selection_clear_model (self);
|
||||
|
||||
g_free (self->property);
|
||||
|
||||
G_OBJECT_CLASS (gtk_property_selection_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_class_init (GtkPropertySelectionClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = gtk_property_selection_real_get_property;
|
||||
gobject_class->set_property = gtk_property_selection_real_set_property;
|
||||
gobject_class->dispose = gtk_property_selection_dispose;
|
||||
|
||||
/**
|
||||
* GtkPropertySelection:model
|
||||
*
|
||||
* The list managed by this selection
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
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);
|
||||
|
||||
properties[PROP_PROPERTY] =
|
||||
g_param_spec_string ("property",
|
||||
P_("Property"),
|
||||
P_("Item property to store selection state in"),
|
||||
NULL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_property_selection_init (GtkPropertySelection *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_property_selection_new:
|
||||
* @model: (transfer none): the #GListModel to manage
|
||||
* @property: the item property to use
|
||||
*
|
||||
* Creates a new property selection to handle @model.
|
||||
*
|
||||
* @property must be the name of a writable boolean property
|
||||
* of the item type of @model.
|
||||
*
|
||||
* Note that GtkPropertySelection does not monitor the property
|
||||
* for changes while the item is part of the model, but it does
|
||||
* inherit the initial value when an item is added to the model.
|
||||
*
|
||||
* Returns: (transfer full) (type GtkPropertySelection): a new #GtkPropertySelection
|
||||
**/
|
||||
GListModel *
|
||||
gtk_property_selection_new (GListModel *model,
|
||||
const char *property)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_PROPERTY_SELECTION,
|
||||
"model", model,
|
||||
"property", property,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_property_selection_get_model:
|
||||
* @self: a #GtkPropertySelection
|
||||
*
|
||||
* Gets the underlying model.
|
||||
*
|
||||
* Returns: (transfer none): the underlying model
|
||||
*/
|
||||
GListModel *
|
||||
gtk_property_selection_get_model (GtkPropertySelection *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_PROPERTY_SELECTION (self), NULL);
|
||||
|
||||
return self->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_property_selection_get_property:
|
||||
* @self: a #GtkPropertySelection
|
||||
*
|
||||
* Gets the name of the item property that @self stores
|
||||
* the selection in.
|
||||
*
|
||||
* Returns: the name of the property
|
||||
*/
|
||||
const char *
|
||||
gtk_property_selection_get_property (GtkPropertySelection *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_PROPERTY_SELECTION (self), NULL);
|
||||
|
||||
return self->property;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_PROPERTY_SELECTION_H__
|
||||
#define __GTK_PROPERTY_SELECTION_H__
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkselectionmodel.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_PROPERTY_SELECTION (gtk_property_selection_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkPropertySelection, gtk_property_selection, GTK, PROPERTY_SELECTION, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_property_selection_new (GListModel *model,
|
||||
const char *property);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_property_selection_get_model (GtkPropertySelection *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gtk_property_selection_get_property (GtkPropertySelection *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PROPERTY_SELECTION_H__ */
|
||||
+2
-13
@@ -546,19 +546,8 @@ gtk_scrolled_window_compute_expand (GtkWidget *widget,
|
||||
gboolean *hexpand,
|
||||
gboolean *vexpand)
|
||||
{
|
||||
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
|
||||
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
|
||||
if (priv->child)
|
||||
{
|
||||
*hexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_HORIZONTAL);
|
||||
*vexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_VERTICAL);
|
||||
}
|
||||
else
|
||||
{
|
||||
*hexpand = FALSE;
|
||||
*vexpand = FALSE;
|
||||
}
|
||||
*hexpand = TRUE;
|
||||
*vexpand = TRUE;
|
||||
}
|
||||
|
||||
static GtkSizeRequestMode
|
||||
|
||||
+14
-6
@@ -49,17 +49,14 @@
|
||||
* @Short_description: An entry which shows a search icon
|
||||
* @Title: GtkSearchEntry
|
||||
*
|
||||
* #GtkSearchEntry is a subclass of #GtkEntry that has been
|
||||
* tailored for use as a search entry.
|
||||
* #GtkSearchEntry is an entry widget that has been tailored for use
|
||||
* as a search entry. The main aPI for interacting with a GtkSearchEntry
|
||||
* as entry is the #GtkEditable interface.
|
||||
*
|
||||
* It will show an inactive symbolic “find” icon when the search
|
||||
* entry is empty, and a symbolic “clear” icon when there is text.
|
||||
* Clicking on the “clear” icon will empty the search entry.
|
||||
*
|
||||
* Note that the search/clear icon is shown using a secondary
|
||||
* icon, and thus does not work if you are using the secondary
|
||||
* icon position for some other purpose.
|
||||
*
|
||||
* To make filtering appear more reactive, it is a good idea to
|
||||
* not react to every change in the entry text immediately, but
|
||||
* only after a short delay. To support this, #GtkSearchEntry
|
||||
@@ -74,6 +71,17 @@
|
||||
* placed inside a #GtkSearchBar. If that is not the case,
|
||||
* you can use gtk_search_entry_set_key_capture_widget() to let it
|
||||
* capture key input from another widget.
|
||||
*
|
||||
* # CSS Nodes
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* entry.search
|
||||
* ╰── text
|
||||
* ]|
|
||||
*
|
||||
* GtkSearchEntry has a single CSS node with name entry that carries
|
||||
* a .sarch style class, and the text node is a child of that.
|
||||
|
||||
*/
|
||||
|
||||
enum {
|
||||
|
||||
+230
-116
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gtkselectionmodel.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmarshalers.h"
|
||||
|
||||
@@ -79,7 +80,33 @@ static gboolean
|
||||
gtk_selection_model_default_is_selected (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return FALSE;
|
||||
GtkBitset *bitset;
|
||||
gboolean selected;
|
||||
|
||||
bitset = gtk_selection_model_get_selection_in_range (model, position, 1);
|
||||
selected = gtk_bitset_contains (bitset, position);
|
||||
gtk_bitset_unref (bitset);
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
static GtkBitset *
|
||||
gtk_selection_model_default_get_selection_in_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkBitset *bitset;
|
||||
guint i;
|
||||
|
||||
bitset = gtk_bitset_new_empty ();
|
||||
|
||||
for (i = position; i < position + n_items; i++)
|
||||
{
|
||||
if (gtk_selection_model_is_selected (model, i))
|
||||
gtk_bitset_add (bitset, i);
|
||||
}
|
||||
|
||||
return bitset;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -87,13 +114,48 @@ gtk_selection_model_default_select_item (GtkSelectionModel *model,
|
||||
guint position,
|
||||
gboolean unselect_rest)
|
||||
{
|
||||
return FALSE;
|
||||
GtkBitset *selected;
|
||||
GtkBitset *mask;
|
||||
gboolean result;
|
||||
|
||||
selected = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add (selected, position);
|
||||
if (unselect_rest)
|
||||
{
|
||||
mask = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add_range (mask, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = gtk_bitset_ref (selected);
|
||||
}
|
||||
|
||||
result = gtk_selection_model_set_selection (model, selected, mask);
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
gtk_bitset_unref (mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_selection_model_default_unselect_item (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return FALSE;
|
||||
GtkBitset *selected;
|
||||
GtkBitset *mask;
|
||||
gboolean result;
|
||||
|
||||
selected = gtk_bitset_new_empty ();
|
||||
mask = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add (mask, position);
|
||||
|
||||
result = gtk_selection_model_set_selection (model, selected, mask);
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
gtk_bitset_unref (mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -102,7 +164,28 @@ gtk_selection_model_default_select_range (GtkSelectionModel *model,
|
||||
guint n_items,
|
||||
gboolean unselect_rest)
|
||||
{
|
||||
return FALSE;
|
||||
GtkBitset *selected;
|
||||
GtkBitset *mask;
|
||||
gboolean result;
|
||||
|
||||
selected = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add_range (selected, position, n_items);
|
||||
if (unselect_rest)
|
||||
{
|
||||
mask = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add_range (mask, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = gtk_bitset_ref (selected);
|
||||
}
|
||||
|
||||
result = gtk_selection_model_set_selection (model, selected, mask);
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
gtk_bitset_unref (mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -110,24 +193,20 @@ gtk_selection_model_default_unselect_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
GtkBitset *selected;
|
||||
GtkBitset *mask;
|
||||
gboolean result;
|
||||
|
||||
static gboolean
|
||||
gtk_selection_model_default_select_callback (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
selected = gtk_bitset_new_empty ();
|
||||
mask = gtk_bitset_new_empty ();
|
||||
gtk_bitset_add_range (mask, position, n_items);
|
||||
|
||||
static gboolean
|
||||
gtk_selection_model_default_unselect_callback (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
return FALSE;
|
||||
result = gtk_selection_model_set_selection (model, selected, mask);
|
||||
|
||||
gtk_bitset_unref (selected);
|
||||
gtk_bitset_unref (mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -142,40 +221,26 @@ gtk_selection_model_default_unselect_all (GtkSelectionModel *model)
|
||||
return gtk_selection_model_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_selection_model_default_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected)
|
||||
static gboolean
|
||||
gtk_selection_model_default_set_selection (GtkSelectionModel *model,
|
||||
GtkBitset *selected,
|
||||
GtkBitset *mask)
|
||||
{
|
||||
*start_range = position;
|
||||
|
||||
if (position >= g_list_model_get_n_items (G_LIST_MODEL (model)))
|
||||
{
|
||||
*n_items = 0;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*n_items = 1;
|
||||
*selected = gtk_selection_model_is_selected (model, position);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_selection_model_default_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_selection_model_default_is_selected;
|
||||
iface->get_selection_in_range = gtk_selection_model_default_get_selection_in_range;
|
||||
iface->select_item = gtk_selection_model_default_select_item;
|
||||
iface->unselect_item = gtk_selection_model_default_unselect_item;
|
||||
iface->select_range = gtk_selection_model_default_select_range;
|
||||
iface->unselect_range = gtk_selection_model_default_unselect_range;
|
||||
iface->select_all = gtk_selection_model_default_select_all;
|
||||
iface->unselect_all = gtk_selection_model_default_unselect_all;
|
||||
iface->select_callback = gtk_selection_model_default_select_callback;
|
||||
iface->unselect_callback = gtk_selection_model_default_unselect_callback;
|
||||
iface->query_range = gtk_selection_model_default_query_range;
|
||||
iface->set_selection = gtk_selection_model_default_set_selection;
|
||||
|
||||
/**
|
||||
* GtkSelectionModel::selection-changed
|
||||
@@ -225,6 +290,62 @@ gtk_selection_model_is_selected (GtkSelectionModel *model,
|
||||
return iface->is_selected (model, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_get_selection:
|
||||
* @model: a #GtkSelectionModel
|
||||
*
|
||||
* Gets the set containing all currently selected items in the model.
|
||||
*
|
||||
* This function may be slow, so if you are only interested in single item,
|
||||
* consider using gtk_selection_model_is_selected() or if you are only
|
||||
* interested in a few consider gtk_selection_model_get_selection_in_range().
|
||||
*
|
||||
* Returns: (transfer full): a #GtkBitset containing all the values currently
|
||||
* selected in @model. If no items are selected, the bitset is empty.
|
||||
* The bitset must not be modified.
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_selection_model_get_selection (GtkSelectionModel *model)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ());
|
||||
|
||||
return gtk_selection_model_get_selection_in_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_get_selection_in_range:
|
||||
* @model: a #GtkSelectionModel
|
||||
* @position: start of the queired range
|
||||
* @n_items: number of items in the queried range
|
||||
*
|
||||
* Gets a set containing a set where the values in the range [position,
|
||||
* position + n_items) match the selected state of the items in that range.
|
||||
* All values outside that range are undefined.
|
||||
*
|
||||
* This function is an optimization for gtk_selection_model_get_selection() when
|
||||
* you are only interested in part of the model's selected state. A common use
|
||||
* case is in response to the :selection-changed signal.
|
||||
*
|
||||
* Returns: A #GtkBitset that matches the selection state for the given state
|
||||
* with all other values being undefined.
|
||||
* The bitset must not be modified.
|
||||
**/
|
||||
GtkBitset *
|
||||
gtk_selection_model_get_selection_in_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ());
|
||||
|
||||
if (n_items == 0)
|
||||
return gtk_bitset_new_empty ();
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->get_selection_in_range (model, position, n_items);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_select_item:
|
||||
* @model: a #GtkSelectionModel
|
||||
@@ -232,6 +353,9 @@ gtk_selection_model_is_selected (GtkSelectionModel *model,
|
||||
* @unselect_rest: whether previously selected items should be unselected
|
||||
*
|
||||
* Requests to select an item in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean the item was selected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_select_item (GtkSelectionModel *model,
|
||||
@@ -240,7 +364,7 @@ gtk_selection_model_select_item (GtkSelectionModel *model,
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->select_item (model, position, unselect_rest);
|
||||
@@ -252,6 +376,9 @@ gtk_selection_model_select_item (GtkSelectionModel *model,
|
||||
* @position: the position of the item to unselect
|
||||
*
|
||||
* Requests to unselect an item in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean the item was unselected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_unselect_item (GtkSelectionModel *model,
|
||||
@@ -259,7 +386,7 @@ gtk_selection_model_unselect_item (GtkSelectionModel *model,
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->unselect_item (model, position);
|
||||
@@ -273,6 +400,9 @@ gtk_selection_model_unselect_item (GtkSelectionModel *model,
|
||||
* @unselect_rest: whether previously selected items should be unselected
|
||||
*
|
||||
* Requests to select a range of items in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean the range was selected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_select_range (GtkSelectionModel *model,
|
||||
@@ -282,7 +412,7 @@ gtk_selection_model_select_range (GtkSelectionModel *model,
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->select_range (model, position, n_items, unselect_rest);
|
||||
@@ -295,6 +425,9 @@ gtk_selection_model_select_range (GtkSelectionModel *model,
|
||||
* @n_items: the number of items to unselect
|
||||
*
|
||||
* Requests to unselect a range of items in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean the range was unselected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_unselect_range (GtkSelectionModel *model,
|
||||
@@ -303,7 +436,7 @@ gtk_selection_model_unselect_range (GtkSelectionModel *model,
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->unselect_range (model, position, n_items);
|
||||
@@ -314,13 +447,16 @@ gtk_selection_model_unselect_range (GtkSelectionModel *model,
|
||||
* @model: a #GtkSelectionModel
|
||||
*
|
||||
* Requests to select all items in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean that all items are now selected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_select_all (GtkSelectionModel *model)
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->select_all (model);
|
||||
@@ -331,96 +467,74 @@ gtk_selection_model_select_all (GtkSelectionModel *model)
|
||||
* @model: a #GtkSelectionModel
|
||||
*
|
||||
* Requests to unselect all items in the model.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean that all items are now unselected.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_unselect_all (GtkSelectionModel *model)
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), 0);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->unselect_all (model);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_select_callback:
|
||||
* gtk_selection_model_set_selection:
|
||||
* @model: a #GtkSelectionModel
|
||||
* @unselect_rest: whether previously selected items should be unselected
|
||||
* @callback: (scope call): a #GtkSelectionCallback to determine items to select
|
||||
* @data: data to pass to @callback
|
||||
* @selected: bitmask specifying if items should be selected or
|
||||
* unselected
|
||||
* @mask: bitmask specifying which items should be updated
|
||||
*
|
||||
* Requests to select all items for which @callback returns
|
||||
* @selected as TRUE.
|
||||
*/
|
||||
* This is the most advanced selection updating method that allows
|
||||
* the most fine-grained control over selection changes.
|
||||
* If you can, you should try the simpler versions, as implementations
|
||||
* are more likely to implement support for those.
|
||||
*
|
||||
* Requests that the selection state of all positions set in @mask be
|
||||
* updated to the respecitve value in the @selected bitmask.
|
||||
*
|
||||
* In pseudocode, it would look something like this:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* for (i = 0; i < n_items; i++)
|
||||
* {
|
||||
* // don't change values not in the mask
|
||||
* if (!gtk_bitset_contains (mask, i))
|
||||
* continue;
|
||||
*
|
||||
* if (gtk_bitset_contains (selected, i))
|
||||
* select_item (i);
|
||||
* else
|
||||
* unselect_item (i);
|
||||
* }
|
||||
*
|
||||
* gtk_selection_model_selection_changed (model, first_changed_item, n_changed_items);
|
||||
* ]|
|
||||
*
|
||||
* @mask and @selected must not be modified. They may refer to the same bitset,
|
||||
* which would mean that every item in the set should be selected.
|
||||
*
|
||||
* Returns: %TRUE if this action was supported and no fallback should be
|
||||
* tried. This does not mean that all items were updated according
|
||||
* to the inputs.
|
||||
**/
|
||||
gboolean
|
||||
gtk_selection_model_select_callback (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
return GTK_SELECTION_MODEL_GET_IFACE (model)->select_callback (model, unselect_rest, callback, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_unselect_callback:
|
||||
* @model: a #GtkSelectionModel
|
||||
* @callback: (scope call): a #GtkSelectionCallback to determine items to select
|
||||
* @data: data to pass to @callback
|
||||
*
|
||||
* Requests to unselect all items for which @callback returns
|
||||
* @selected as TRUE.
|
||||
*/
|
||||
gboolean
|
||||
gtk_selection_model_unselect_callback (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
|
||||
return GTK_SELECTION_MODEL_GET_IFACE (model)->unselect_callback (model, callback, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_model_query_range:
|
||||
* @model: a #GtkSelectionModel
|
||||
* @position: the position inside the range
|
||||
* @start_range: (out): returns the position of the first element of the range
|
||||
* @n_items: (out): returns the size of the range
|
||||
* @selected: (out): returns whether items in @range are selected
|
||||
*
|
||||
* This function allows to query the selection status of multiple elements at once.
|
||||
* It is passed a position and returns a range of elements of uniform selection status.
|
||||
*
|
||||
* If @position is greater than the number of items in @model, @n_items is set to 0.
|
||||
* Otherwise the returned range is guaranteed to include the passed-in position, so
|
||||
* @n_items will be >= 1.
|
||||
*
|
||||
* Positions directly adjacent to the returned range may have the same selection
|
||||
* status as the returned range.
|
||||
*
|
||||
* This is an optimization function to make iterating over a model faster when few
|
||||
* items are selected. However, it is valid behavior for implementations to use a
|
||||
* naive implementation that only ever returns a single element.
|
||||
*/
|
||||
void
|
||||
gtk_selection_model_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected)
|
||||
gtk_selection_model_set_selection (GtkSelectionModel *model,
|
||||
GtkBitset *selected,
|
||||
GtkBitset *mask)
|
||||
{
|
||||
GtkSelectionModelInterface *iface;
|
||||
|
||||
g_return_if_fail (GTK_IS_SELECTION_MODEL (model));
|
||||
g_return_if_fail (start_range != NULL);
|
||||
g_return_if_fail (n_items != NULL);
|
||||
g_return_if_fail (selected != NULL);
|
||||
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), FALSE);
|
||||
g_return_val_if_fail (selected != NULL, FALSE);
|
||||
g_return_val_if_fail (mask != NULL, FALSE);
|
||||
|
||||
iface = GTK_SELECTION_MODEL_GET_IFACE (model);
|
||||
return iface->query_range (model, position, start_range, n_items, selected);
|
||||
return iface->set_selection (model, selected, mask);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+34
-63
@@ -24,7 +24,7 @@
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -33,39 +33,12 @@ G_BEGIN_DECLS
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_INTERFACE (GtkSelectionModel, gtk_selection_model, GTK, SELECTION_MODEL, GListModel)
|
||||
|
||||
/**
|
||||
* GtkSelectionCallback:
|
||||
* @position: the position to query
|
||||
* @start_range: (out): returns the position of the first element of the range
|
||||
* @n_items: (out): returns the size of the range
|
||||
* @selected: (out): returns whether items in @range are selected
|
||||
* @data: callback data
|
||||
*
|
||||
* Callback type for determining items to operate on with
|
||||
* gtk_selection_model_select_callback() or
|
||||
* gtk_selection_model_unselect_callback().
|
||||
*
|
||||
* The callback determines a range of consecutive items around
|
||||
* @position which should either all
|
||||
* be changed, in which case @selected is set to %TRUE, or all not
|
||||
* be changed, in which case @selected is set to %FALSE.
|
||||
*
|
||||
* @start_range and @n_items are set to return the range.
|
||||
*
|
||||
* The callback will be called repeatedly to find all ranges
|
||||
* to operate on until it has exhausted the items of the model,
|
||||
* or until it returns an empty range (ie @n_items == 0).
|
||||
*/
|
||||
typedef void (* GtkSelectionCallback) (guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected,
|
||||
gpointer data);
|
||||
|
||||
|
||||
/**
|
||||
* GtkSelectionModelInterface:
|
||||
* @is_selected: Return if the item at the given position is selected.
|
||||
* @get_selection_in_range: Return a bitset with all currently selected
|
||||
* items in the given range. By default, this function will call
|
||||
* #GtkSelectionModel::is_selected() on all items in the given range.
|
||||
* @select_item: Select the item in the given position. If the operation
|
||||
* is known to fail, return %FALSE.
|
||||
* @unselect_item: Unselect the item in the given position. If the
|
||||
@@ -79,12 +52,22 @@ typedef void (* GtkSelectionCallback) (guint position,
|
||||
* unsupported or known to fail for all items, return %FALSE.
|
||||
* @unselect_all: Unselect all items in the model. If the operation is
|
||||
* unsupported or known to fail for all items, return %FALSE.
|
||||
* @set_selection: Set selection state of all items in mask to selected.
|
||||
* See gtk_selection_model_set_selection() for a detailed explanation
|
||||
* of this function.
|
||||
*
|
||||
* The list of virtual functions for the #GtkSelectionModel interface.
|
||||
* All getter functions are mandatory to implement, but the model does
|
||||
* not need to implement any functions to support selecting or unselecting
|
||||
* items. Of course, if the model does not do that, it means that users
|
||||
* cannot select or unselect items in a list widgets using the model.
|
||||
* No function must be implemented, but unless #GtkSelectionModel::is_selected()
|
||||
* is implemented, it will not be possible to select items in the set.
|
||||
*
|
||||
* The model does not need to implement any functions to support either
|
||||
* selecting or unselecting items. Of course, if the model does not do that,
|
||||
* it means that users cannot select or unselect items in a list widget
|
||||
* using the model.
|
||||
*
|
||||
* All selection functions fall back to #GtkSelectionModel::set_selection()
|
||||
* so it is sufficient to implement just that function for full selection
|
||||
* support.
|
||||
*/
|
||||
struct _GtkSelectionModelInterface
|
||||
{
|
||||
@@ -94,6 +77,9 @@ struct _GtkSelectionModelInterface
|
||||
/*< public >*/
|
||||
gboolean (* is_selected) (GtkSelectionModel *model,
|
||||
guint position);
|
||||
GtkBitset * (* get_selection_in_range) (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items);
|
||||
|
||||
gboolean (* select_item) (GtkSelectionModel *model,
|
||||
guint position,
|
||||
@@ -109,23 +95,21 @@ struct _GtkSelectionModelInterface
|
||||
guint n_items);
|
||||
gboolean (* select_all) (GtkSelectionModel *model);
|
||||
gboolean (* unselect_all) (GtkSelectionModel *model);
|
||||
gboolean (* select_callback) (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data);
|
||||
gboolean (* unselect_callback) (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data);
|
||||
void (* query_range) (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected);
|
||||
gboolean (* set_selection) (GtkSelectionModel *model,
|
||||
GtkBitset *selected,
|
||||
GtkBitset *mask);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_is_selected (GtkSelectionModel *model,
|
||||
guint position);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_selection_model_get_selection (GtkSelectionModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkBitset * gtk_selection_model_get_selection_in_range
|
||||
(GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_select_item (GtkSelectionModel *model,
|
||||
@@ -147,23 +131,10 @@ GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_select_all (GtkSelectionModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_unselect_all (GtkSelectionModel *model);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_select_callback (GtkSelectionModel *model,
|
||||
gboolean unselect_rest,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_selection_model_unselect_callback (GtkSelectionModel *model,
|
||||
GtkSelectionCallback callback,
|
||||
gpointer data);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_selection_model_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected);
|
||||
gboolean gtk_selection_model_set_selection (GtkSelectionModel *model,
|
||||
GtkBitset *selected,
|
||||
GtkBitset *mask);
|
||||
|
||||
/* for implementations only */
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
||||
-383
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "gtkset.h"
|
||||
|
||||
/* Store a set of unsigned integers as a sorted array of ranges.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint first;
|
||||
guint n_items;
|
||||
} Range;
|
||||
|
||||
struct _GtkSet
|
||||
{
|
||||
GArray *ranges;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkSet *set;
|
||||
Range *current;
|
||||
int idx;
|
||||
guint pos;
|
||||
} GtkRealSetIter;
|
||||
|
||||
GtkSet *
|
||||
gtk_set_new (void)
|
||||
{
|
||||
GtkSet *set;
|
||||
|
||||
set = g_new (GtkSet, 1);
|
||||
set->ranges = g_array_new (FALSE, FALSE, sizeof (Range));
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
GtkSet *
|
||||
gtk_set_copy (GtkSet *set)
|
||||
{
|
||||
GtkSet *copy;
|
||||
|
||||
copy = g_new (GtkSet, 1);
|
||||
copy->ranges = g_array_copy (set->ranges);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_free (GtkSet *set)
|
||||
{
|
||||
g_array_free (set->ranges, TRUE);
|
||||
g_free (set);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_set_contains (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
|
||||
if (item < r->first)
|
||||
return FALSE;
|
||||
|
||||
if (item < r->first + r->n_items)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_all (GtkSet *set)
|
||||
{
|
||||
g_array_set_size (set->ranges, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
range_compare (Range *r, Range *s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (r->first + r->n_items < s->first)
|
||||
ret = -1;
|
||||
else if (s->first + s->n_items < r->first)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_add_range (GtkSet *set,
|
||||
guint first_item,
|
||||
guint n_items)
|
||||
{
|
||||
int i;
|
||||
Range s;
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
|
||||
s.first = first_item;
|
||||
s.n_items = n_items;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
int cmp = range_compare (&s, r);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (first < 0)
|
||||
first = i;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (first > -1)
|
||||
{
|
||||
Range *r;
|
||||
guint start;
|
||||
guint end;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, first);
|
||||
start = MIN (s.first, r->first);
|
||||
|
||||
r = &g_array_index (set->ranges, Range, last);
|
||||
end = MAX (s.first + s.n_items - 1, r->first + r->n_items - 1);
|
||||
|
||||
s.first = start;
|
||||
s.n_items = end - start + 1;
|
||||
|
||||
g_array_remove_range (set->ranges, first, last - first + 1);
|
||||
g_array_insert_val (set->ranges, first, s);
|
||||
}
|
||||
else
|
||||
g_array_insert_val (set->ranges, i, s);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_range (GtkSet *set,
|
||||
guint first_item,
|
||||
guint n_items)
|
||||
{
|
||||
Range s;
|
||||
int i;
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
|
||||
s.first = first_item;
|
||||
s.n_items = n_items;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
int cmp = range_compare (&s, r);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (first < 0)
|
||||
first = i;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (first > -1)
|
||||
{
|
||||
Range *r;
|
||||
Range a[2];
|
||||
int k = 0;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, first);
|
||||
if (r->first < s.first)
|
||||
{
|
||||
a[k].first = r->first;
|
||||
a[k].n_items = s.first - r->first;
|
||||
k++;
|
||||
}
|
||||
r = &g_array_index (set->ranges, Range, last);
|
||||
if (r->first + r->n_items > s.first + s.n_items)
|
||||
{
|
||||
a[k].first = s.first + s.n_items;
|
||||
a[k].n_items = r->first + r->n_items - a[k].first;
|
||||
k++;
|
||||
}
|
||||
g_array_remove_range (set->ranges, first, last - first + 1);
|
||||
if (k > 0)
|
||||
g_array_insert_vals (set->ranges, first, a, k);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_find_range (GtkSet *set,
|
||||
guint position,
|
||||
guint upper_bound,
|
||||
guint *start,
|
||||
guint *n_items,
|
||||
gboolean *contained)
|
||||
{
|
||||
int i;
|
||||
int last = 0;
|
||||
|
||||
if (position >= upper_bound)
|
||||
{
|
||||
*start = 0;
|
||||
*n_items = 0;
|
||||
*contained = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
|
||||
if (position < r->first)
|
||||
{
|
||||
*start = last;
|
||||
*n_items = r->first - last;
|
||||
*contained = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (r->first <= position && position < r->first + r->n_items)
|
||||
{
|
||||
*start = r->first;
|
||||
*n_items = r->n_items;
|
||||
*contained = TRUE;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
last = r->first + r->n_items;
|
||||
}
|
||||
|
||||
*start = last;
|
||||
*n_items = upper_bound - last;
|
||||
*contained = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_add_item (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
gtk_set_add_range (set, item, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_item (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
gtk_set_remove_range (set, item, 1);
|
||||
}
|
||||
|
||||
/* This is peculiar operation: Replace every number n >= first by n + shift
|
||||
* This is only supported for negative shifts if the shifting does not cause
|
||||
* any ranges to overlap.
|
||||
*/
|
||||
void
|
||||
gtk_set_shift (GtkSet *set,
|
||||
guint first,
|
||||
int shift)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
if (r->first >= first)
|
||||
r->first += shift;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_iter_init (GtkSetIter *iter,
|
||||
GtkSet *set)
|
||||
{
|
||||
GtkRealSetIter *ri = (GtkRealSetIter *)iter;
|
||||
|
||||
ri->set = set;
|
||||
ri->idx = -1;
|
||||
ri->current = 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_set_iter_next (GtkSetIter *iter,
|
||||
guint *item)
|
||||
{
|
||||
GtkRealSetIter *ri = (GtkRealSetIter *)iter;
|
||||
|
||||
if (ri->idx == -1)
|
||||
{
|
||||
next_range:
|
||||
ri->idx++;
|
||||
|
||||
if (ri->idx == ri->set->ranges->len)
|
||||
return FALSE;
|
||||
|
||||
ri->current = &g_array_index (ri->set->ranges, Range, ri->idx);
|
||||
ri->pos = ri->current->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri->pos++;
|
||||
if (ri->pos == ri->current->first + ri->current->n_items)
|
||||
goto next_range;
|
||||
}
|
||||
|
||||
*item = ri->pos;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_set_is_empty (GtkSet *set)
|
||||
{
|
||||
return set->ranges->len == 0;
|
||||
}
|
||||
|
||||
guint
|
||||
gtk_set_get_min (GtkSet *set)
|
||||
{
|
||||
Range *r;
|
||||
|
||||
if (gtk_set_is_empty (set))
|
||||
return 0;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, 0);
|
||||
|
||||
return r->first;
|
||||
}
|
||||
|
||||
guint
|
||||
gtk_set_get_max (GtkSet *set)
|
||||
{
|
||||
Range *r;
|
||||
|
||||
if (gtk_set_is_empty (set))
|
||||
return 0;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, set->ranges->len - 1);
|
||||
|
||||
return r->first + r->n_items - 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
gtk_set_dump (GtkSet *set)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
g_print (" %u:%u", r->first, r->n_items);
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
#endif
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SET_H__
|
||||
#define __GTK_SET_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct _GtkSet GtkSet;
|
||||
typedef struct _GtkSetIter GtkSetIter;
|
||||
|
||||
struct _GtkSetIter
|
||||
{
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
int dummy3;
|
||||
int dummy4;
|
||||
};
|
||||
|
||||
GtkSet *gtk_set_new (void);
|
||||
void gtk_set_free (GtkSet *set);
|
||||
GtkSet *gtk_set_copy (GtkSet *set);
|
||||
|
||||
gboolean gtk_set_contains (GtkSet *set,
|
||||
guint item);
|
||||
|
||||
void gtk_set_remove_all (GtkSet *set);
|
||||
void gtk_set_add_item (GtkSet *set,
|
||||
guint item);
|
||||
void gtk_set_remove_item (GtkSet *set,
|
||||
guint item);
|
||||
void gtk_set_add_range (GtkSet *set,
|
||||
guint first,
|
||||
guint n);
|
||||
void gtk_set_remove_range (GtkSet *set,
|
||||
guint first,
|
||||
guint n);
|
||||
void gtk_set_find_range (GtkSet *set,
|
||||
guint position,
|
||||
guint upper_bound,
|
||||
guint *start,
|
||||
guint *n_items,
|
||||
gboolean *contained);
|
||||
|
||||
void gtk_set_shift (GtkSet *set,
|
||||
guint first,
|
||||
int shift);
|
||||
|
||||
void gtk_set_iter_init (GtkSetIter *iter,
|
||||
GtkSet *set);
|
||||
gboolean gtk_set_iter_next (GtkSetIter *iter,
|
||||
guint *item);
|
||||
|
||||
gboolean gtk_set_is_empty (GtkSet *set);
|
||||
guint gtk_set_get_min (GtkSet *set);
|
||||
guint gtk_set_get_max (GtkSet *set);
|
||||
|
||||
#endif /* __GTK_SET_H__ */
|
||||
@@ -159,7 +159,7 @@ gtk_shortcut_action_activate (GtkShortcutAction *self,
|
||||
g_return_val_if_fail (GTK_IS_SHORTCUT_ACTION (self), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
GTK_NOTE (SHORTCUTS, {
|
||||
GTK_NOTE (KEYBINDINGS, {
|
||||
char *act = gtk_shortcut_action_to_string (self);
|
||||
g_print ("Shortcut action activate on %s: %s\n", G_OBJECT_TYPE_NAME (widget), act);
|
||||
g_free (act);
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkdebug.h"
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
|
||||
@@ -370,6 +371,18 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
|
||||
data->widget = widget;
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GTK_DEBUG_CHECK (KEYBINDINGS))
|
||||
{
|
||||
g_message ("Found %u shortcuts triggered %s by %s %u %u",
|
||||
shortcuts ? shortcuts->len : 0,
|
||||
has_exact ? "exactly" : "approximately",
|
||||
gdk_event_get_event_type (event) == GDK_KEY_PRESS ? "key press" : "key release",
|
||||
gdk_key_event_get_keyval (event),
|
||||
gdk_event_get_modifier_state (event));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!shortcuts)
|
||||
return retval;
|
||||
|
||||
|
||||
+17
-45
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "gtksingleselection.h"
|
||||
|
||||
#include "gtkbitset.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
|
||||
@@ -110,6 +111,21 @@ gtk_single_selection_is_selected (GtkSelectionModel *model,
|
||||
return self->selected == position;
|
||||
}
|
||||
|
||||
static GtkBitset *
|
||||
gtk_single_selection_get_selection_in_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkSingleSelection *self = GTK_SINGLE_SELECTION (model);
|
||||
GtkBitset *result;
|
||||
|
||||
result = gtk_bitset_new_empty ();
|
||||
if (self->selected != GTK_INVALID_LIST_POSITION)
|
||||
gtk_bitset_add (result, self->selected);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_single_selection_select_item (GtkSelectionModel *model,
|
||||
guint position,
|
||||
@@ -138,57 +154,13 @@ gtk_single_selection_unselect_item (GtkSelectionModel *model,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_single_selection_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_range,
|
||||
gboolean *selected)
|
||||
{
|
||||
GtkSingleSelection *self = GTK_SINGLE_SELECTION (model);
|
||||
guint n_items;
|
||||
|
||||
n_items = g_list_model_get_n_items (self->model);
|
||||
|
||||
if (position >= n_items)
|
||||
{
|
||||
*start_range = position;
|
||||
*n_range = 0;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (self->selected == GTK_INVALID_LIST_POSITION)
|
||||
{
|
||||
*start_range = 0;
|
||||
*n_range = n_items;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (position < self->selected)
|
||||
{
|
||||
*start_range = 0;
|
||||
*n_range = self->selected;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else if (position > self->selected)
|
||||
{
|
||||
*start_range = self->selected + 1;
|
||||
*n_range = n_items - *start_range;
|
||||
*selected = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*start_range = self->selected;
|
||||
*n_range = 1;
|
||||
*selected = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_single_selection_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_single_selection_is_selected;
|
||||
iface->get_selection_in_range = gtk_single_selection_get_selection_in_range;
|
||||
iface->select_item = gtk_single_selection_select_item;
|
||||
iface->unselect_item = gtk_single_selection_unselect_item;
|
||||
iface->query_range = gtk_single_selection_query_range;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkSingleSelection, gtk_single_selection, G_TYPE_OBJECT, 0,
|
||||
|
||||
+115
-32
@@ -34,6 +34,11 @@
|
||||
|
||||
#include "gtk/gskpango.h"
|
||||
|
||||
#define GTK_VECTOR_NAME gtk_snapshot_nodes
|
||||
#define GTK_VECTOR_TYPE_NAME GtkSnapshotNodes
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GskRenderNode *
|
||||
#define GTK_VECTOR_FREE_FUNC gsk_render_node_unref
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtksnapshot
|
||||
@@ -54,6 +59,85 @@
|
||||
* use gtk_snapshot_new().
|
||||
*/
|
||||
|
||||
typedef struct _GtkSnapshotState GtkSnapshotState;
|
||||
|
||||
typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
GskRenderNode **nodes,
|
||||
guint n_nodes);
|
||||
|
||||
struct _GtkSnapshotState {
|
||||
guint start_node_index;
|
||||
guint n_nodes;
|
||||
|
||||
GskTransform * transform;
|
||||
|
||||
GtkSnapshotCollectFunc collect_func;
|
||||
union {
|
||||
struct {
|
||||
double opacity;
|
||||
} opacity;
|
||||
struct {
|
||||
double radius;
|
||||
} blur;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t child_bounds;
|
||||
} repeat;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
} clip;
|
||||
struct {
|
||||
GskRoundedRect bounds;
|
||||
} rounded_clip;
|
||||
struct {
|
||||
gsize n_shadows;
|
||||
GskShadow *shadows;
|
||||
GskShadow a_shadow; /* Used if n_shadows == 1 */
|
||||
} shadow;
|
||||
struct {
|
||||
GskBlendMode blend_mode;
|
||||
GskRenderNode *bottom_node;
|
||||
} blend;
|
||||
struct {
|
||||
double progress;
|
||||
GskRenderNode *start_node;
|
||||
} cross_fade;
|
||||
struct {
|
||||
char *message;
|
||||
} debug;
|
||||
} data;
|
||||
};
|
||||
|
||||
static void gtk_snapshot_state_clear (GtkSnapshotState *state);
|
||||
|
||||
#define GTK_VECTOR_NAME gtk_snapshot_states
|
||||
#define GTK_VECTOR_TYPE_NAME GtkSnapshotStates
|
||||
#define GTK_VECTOR_ELEMENT_TYPE GtkSnapshotState
|
||||
#define GTK_VECTOR_FREE_FUNC gtk_snapshot_state_clear
|
||||
#define GTK_VECTOR_BY_VALUE 1
|
||||
#include "gtkvectorimpl.c"
|
||||
|
||||
/* This is a nasty little hack. We typedef GtkSnapshot to the fake object GdkSnapshot
|
||||
* so that we don't need to typecast between them.
|
||||
* After all, the GdkSnapshot only exist so poor language bindings don't trip. Hardcore
|
||||
* C code can just blatantly ignore such layering violations with a typedef.
|
||||
*/
|
||||
struct _GdkSnapshot {
|
||||
GObject parent_instance; /* it's really GdkSnapshot, but don't tell anyone! */
|
||||
|
||||
GtkSnapshotStates state_stack;
|
||||
GtkSnapshotNodes nodes;
|
||||
};
|
||||
|
||||
struct _GtkSnapshotClass {
|
||||
GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkSnapshot, gtk_snapshot, GDK_TYPE_SNAPSHOT)
|
||||
|
||||
static void
|
||||
@@ -61,11 +145,11 @@ gtk_snapshot_dispose (GObject *object)
|
||||
{
|
||||
GtkSnapshot *snapshot = GTK_SNAPSHOT (object);
|
||||
|
||||
if (snapshot->state_stack)
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
gsk_render_node_unref (gtk_snapshot_to_node (snapshot));
|
||||
|
||||
g_assert (snapshot->state_stack == NULL);
|
||||
g_assert (snapshot->nodes == NULL);
|
||||
g_assert (gtk_snapshot_states_is_empty (&snapshot->state_stack));
|
||||
g_assert (gtk_snapshot_nodes_is_empty (&snapshot->nodes));
|
||||
|
||||
G_OBJECT_CLASS (gtk_snapshot_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -112,15 +196,15 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
GskTransform *transform,
|
||||
GtkSnapshotCollectFunc collect_func)
|
||||
{
|
||||
const gsize n_states = snapshot->state_stack->len;
|
||||
const gsize n_states = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
GtkSnapshotState *state;
|
||||
|
||||
g_array_set_size (snapshot->state_stack, n_states + 1);
|
||||
state = &g_array_index (snapshot->state_stack, GtkSnapshotState, n_states);
|
||||
gtk_snapshot_states_set_size (&snapshot->state_stack, n_states + 1);
|
||||
state = gtk_snapshot_states_get (&snapshot->state_stack, n_states);
|
||||
|
||||
state->transform = gsk_transform_ref (transform);
|
||||
state->collect_func = collect_func;
|
||||
state->start_node_index = snapshot->nodes->len;
|
||||
state->start_node_index = gtk_snapshot_nodes_get_size (&snapshot->nodes);
|
||||
state->n_nodes = 0;
|
||||
|
||||
return state;
|
||||
@@ -129,17 +213,21 @@ gtk_snapshot_push_state (GtkSnapshot *snapshot,
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_current_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
g_assert (snapshot->state_stack->len > 0);
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 1);
|
||||
g_assert (size > 0);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 1);
|
||||
}
|
||||
|
||||
static GtkSnapshotState *
|
||||
gtk_snapshot_get_previous_state (const GtkSnapshot *snapshot)
|
||||
{
|
||||
g_assert (snapshot->state_stack->len > 1);
|
||||
gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
|
||||
|
||||
return &g_array_index (snapshot->state_stack, GtkSnapshotState, snapshot->state_stack->len - 2);
|
||||
g_assert (size > 1);
|
||||
|
||||
return gtk_snapshot_states_get (&snapshot->state_stack, size - 2);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -162,9 +250,8 @@ gtk_snapshot_new (void)
|
||||
|
||||
snapshot = g_object_new (GTK_TYPE_SNAPSHOT, NULL);
|
||||
|
||||
snapshot->state_stack = g_array_new (FALSE, TRUE, sizeof (GtkSnapshotState));
|
||||
g_array_set_clear_func (snapshot->state_stack, (GDestroyNotify)gtk_snapshot_state_clear);
|
||||
snapshot->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_render_node_unref);
|
||||
gtk_snapshot_states_init (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_init (&snapshot->nodes);
|
||||
|
||||
gtk_snapshot_push_state (snapshot,
|
||||
NULL,
|
||||
@@ -1029,30 +1116,28 @@ gtk_snapshot_pop_one (GtkSnapshot *snapshot)
|
||||
guint state_index;
|
||||
GskRenderNode *node;
|
||||
|
||||
if (snapshot->state_stack->len == 0)
|
||||
if (gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_pop() calls.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state = gtk_snapshot_get_current_state (snapshot);
|
||||
state_index = snapshot->state_stack->len - 1;
|
||||
state_index = gtk_snapshot_states_get_size (&snapshot->state_stack) - 1;
|
||||
|
||||
if (state->collect_func)
|
||||
{
|
||||
node = state->collect_func (snapshot,
|
||||
state,
|
||||
(GskRenderNode **) snapshot->nodes->pdata + state->start_node_index,
|
||||
(GskRenderNode **) gtk_snapshot_nodes_index (&snapshot->nodes, state->start_node_index),
|
||||
state->n_nodes);
|
||||
|
||||
/* The collect func may not modify the state stack... */
|
||||
g_assert (state_index == snapshot->state_stack->len - 1);
|
||||
g_assert (state_index == gtk_snapshot_states_get_size (&snapshot->state_stack) - 1);
|
||||
|
||||
/* Remove all the state's nodes from the list of nodes */
|
||||
g_assert (state->start_node_index + state->n_nodes == snapshot->nodes->len);
|
||||
g_ptr_array_remove_range (snapshot->nodes,
|
||||
snapshot->nodes->len - state->n_nodes,
|
||||
state->n_nodes);
|
||||
g_assert (state->start_node_index + state->n_nodes == gtk_snapshot_nodes_get_size (&snapshot->nodes));
|
||||
gtk_snapshot_nodes_splice (&snapshot->nodes, state->start_node_index, state->n_nodes, NULL, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1063,10 +1148,10 @@ gtk_snapshot_pop_one (GtkSnapshot *snapshot)
|
||||
/* move the nodes to the parent */
|
||||
previous_state = gtk_snapshot_get_previous_state (snapshot);
|
||||
previous_state->n_nodes += state->n_nodes;
|
||||
g_assert (previous_state->start_node_index + previous_state->n_nodes == snapshot->nodes->len);
|
||||
g_assert (previous_state->start_node_index + previous_state->n_nodes == gtk_snapshot_nodes_get_size (&snapshot->nodes));
|
||||
}
|
||||
|
||||
g_array_remove_index (snapshot->state_stack, state_index);
|
||||
gtk_snapshot_states_splice (&snapshot->state_stack, state_index, 1, NULL, 0);
|
||||
|
||||
return node;
|
||||
}
|
||||
@@ -1081,7 +1166,7 @@ gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
|
||||
|
||||
if (current_state)
|
||||
{
|
||||
g_ptr_array_add (snapshot->nodes, node);
|
||||
gtk_snapshot_nodes_append (&snapshot->nodes, node);
|
||||
current_state->n_nodes ++;
|
||||
}
|
||||
else
|
||||
@@ -1162,16 +1247,14 @@ gtk_snapshot_to_node (GtkSnapshot *snapshot)
|
||||
result = gtk_snapshot_pop_internal (snapshot);
|
||||
|
||||
/* We should have exactly our initial state */
|
||||
if (snapshot->state_stack->len > 0)
|
||||
if (!gtk_snapshot_states_is_empty (&snapshot->state_stack))
|
||||
{
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %u states remaining.", snapshot->state_stack->len);
|
||||
g_warning ("Too many gtk_snapshot_push() calls. %zu states remaining.",
|
||||
gtk_snapshot_states_get_size (&snapshot->state_stack));
|
||||
}
|
||||
|
||||
g_array_free (snapshot->state_stack, TRUE);
|
||||
g_ptr_array_free (snapshot->nodes, TRUE);
|
||||
|
||||
snapshot->state_stack = NULL;
|
||||
snapshot->nodes = NULL;
|
||||
gtk_snapshot_states_clear (&snapshot->state_stack);
|
||||
gtk_snapshot_nodes_clear (&snapshot->nodes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -24,76 +24,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkSnapshotState GtkSnapshotState;
|
||||
|
||||
typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot *snapshot,
|
||||
GtkSnapshotState *state,
|
||||
GskRenderNode **nodes,
|
||||
guint n_nodes);
|
||||
|
||||
struct _GtkSnapshotState {
|
||||
guint start_node_index;
|
||||
guint n_nodes;
|
||||
|
||||
GskTransform * transform;
|
||||
|
||||
GtkSnapshotCollectFunc collect_func;
|
||||
union {
|
||||
struct {
|
||||
double opacity;
|
||||
} opacity;
|
||||
struct {
|
||||
double radius;
|
||||
} blur;
|
||||
struct {
|
||||
graphene_matrix_t matrix;
|
||||
graphene_vec4_t offset;
|
||||
} color_matrix;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
graphene_rect_t child_bounds;
|
||||
} repeat;
|
||||
struct {
|
||||
graphene_rect_t bounds;
|
||||
} clip;
|
||||
struct {
|
||||
GskRoundedRect bounds;
|
||||
} rounded_clip;
|
||||
struct {
|
||||
gsize n_shadows;
|
||||
GskShadow *shadows;
|
||||
GskShadow a_shadow; /* Used if n_shadows == 1 */
|
||||
} shadow;
|
||||
struct {
|
||||
GskBlendMode blend_mode;
|
||||
GskRenderNode *bottom_node;
|
||||
} blend;
|
||||
struct {
|
||||
double progress;
|
||||
GskRenderNode *start_node;
|
||||
} cross_fade;
|
||||
struct {
|
||||
char *message;
|
||||
} debug;
|
||||
} data;
|
||||
};
|
||||
|
||||
/* This is a nasty little hack. We typedef GtkSnapshot to the fake object GdkSnapshot
|
||||
* so that we don't need to typecast between them.
|
||||
* After all, the GdkSnapshot only exist so poor language bindings don't trip. Hardcore
|
||||
* C code can just blatantly ignore such layering violations with a typedef.
|
||||
*/
|
||||
struct _GdkSnapshot {
|
||||
GObject parent_instance; /* it's really GdkSnapshot, but don't tell anyone! */
|
||||
|
||||
GArray *state_stack;
|
||||
GPtrArray *nodes;
|
||||
};
|
||||
|
||||
struct _GtkSnapshotClass {
|
||||
GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
|
||||
};
|
||||
|
||||
void gtk_snapshot_append_text (GtkSnapshot *snapshot,
|
||||
PangoFont *font,
|
||||
PangoGlyphString *glyphs,
|
||||
|
||||
+2
-5
@@ -31,12 +31,9 @@ G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GtkSorterOrder:
|
||||
* @GTK_SORTER_ORDER_PARTIAL: A partial order. And #GtkOrdering is possible.
|
||||
* @GTK_SORTER_ORDER_INVALID: An invalid order. gtk_sorter_compare() will
|
||||
* always return %GTK_ORDERING_INVALID if both items are unequal.
|
||||
* @GTK_SORTER_ORDER_PARTIAL: A partial order. Any #GtkOrdering is possible.
|
||||
* @GTK_SORTER_ORDER_NONE: No order, all elements are considered equal.
|
||||
* gtk_sorter_compare() will only return %GTK_ORDERING_EQUAL or
|
||||
* %GTK_ORDERING_INVALID.
|
||||
* gtk_sorter_compare() will only return %GTK_ORDERING_EQUAL.
|
||||
* @GTK_SORTER_ORDER_TOTAL: A total order. gtk_sorter_compare() will only
|
||||
* return %GTK_ORDERING_EQUAL if an item is compared with itself. Two
|
||||
* different items will never cause this value to be returned.
|
||||
|
||||
+9
-7
@@ -1504,16 +1504,16 @@ gtk_stack_get_child_by_name (GtkStack *stack,
|
||||
|
||||
/**
|
||||
* gtk_stack_page_get_child:
|
||||
* @page: a #GtkStackPage
|
||||
* @self: a #GtkStackPage
|
||||
*
|
||||
* Returns the stack child to which @page belongs.
|
||||
* Returns the stack child to which @self belongs.
|
||||
*
|
||||
* Returns: (transfer none): the child to which @page belongs
|
||||
* Returns: (transfer none): the child to which @self belongs
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_stack_page_get_child (GtkStackPage *page)
|
||||
gtk_stack_page_get_child (GtkStackPage *self)
|
||||
{
|
||||
return page->widget;
|
||||
return self->widget;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2456,11 +2456,13 @@ gtk_stack_get_pages (GtkStack *stack)
|
||||
|
||||
/**
|
||||
* gtk_stack_page_get_visible:
|
||||
* @page: a #GtkStackPage
|
||||
* @self: a #GtkStackPage
|
||||
*
|
||||
* Returns whether @page is visible in its #GtkStack.
|
||||
* This is independent from the #GtkWidget:visible value of its
|
||||
* #GtkWidget.
|
||||
*
|
||||
* Returns: %TRUE if @page is visible
|
||||
*/
|
||||
gboolean
|
||||
gtk_stack_page_get_visible (GtkStackPage *self)
|
||||
@@ -2472,7 +2474,7 @@ gtk_stack_page_get_visible (GtkStackPage *self)
|
||||
|
||||
/**
|
||||
* gtk_stack_page_set_visible:
|
||||
* @page: a #GtkStackPage
|
||||
* @self: a #GtkStackPage
|
||||
* @visible: The new property value
|
||||
*
|
||||
* Sets the new value of the #GtkStackPage:visible property
|
||||
|
||||
+1
-6
@@ -73,7 +73,7 @@ typedef enum {
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_stack_page_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_stack_page_get_child (GtkStackPage *page);
|
||||
GtkWidget * gtk_stack_page_get_child (GtkStackPage *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_stack_page_get_visible (GtkStackPage *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
@@ -146,11 +146,6 @@ void gtk_stack_set_visible_child_full (GtkStack
|
||||
const gchar *name,
|
||||
GtkStackTransitionType transition);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_stack_set_homogeneous (GtkStack *stack,
|
||||
gboolean homogeneous);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_stack_get_homogeneous (GtkStack *stack);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_stack_set_hhomogeneous (GtkStack *stack,
|
||||
gboolean hhomogeneous);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+30
-34
@@ -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,12 @@ gtk_string_object_new_take (char *string)
|
||||
return obj;
|
||||
}
|
||||
|
||||
static GtkStringObject *
|
||||
gtk_string_object_new (const char *string)
|
||||
{
|
||||
return gtk_string_object_new_take (g_strdup (string));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_string_object_get_string:
|
||||
* @self: a #GtkStringObject
|
||||
@@ -425,22 +424,20 @@ gtk_string_list_init (GtkStringList *self)
|
||||
|
||||
/**
|
||||
* gtk_string_list_new:
|
||||
* @strings: (allow-none): The strings to put in the model
|
||||
* @strings: (array zero-terminated=1) (nullable): The strings to put in the model
|
||||
*
|
||||
* Creates a new #GtkStringList with the given @strings.
|
||||
*
|
||||
* 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 +447,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 +463,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 +489,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,7 +530,7 @@ gtk_string_list_append (GtkStringList *self,
|
||||
/**
|
||||
* gtk_string_list_take:
|
||||
* @self: a #GtkStringList
|
||||
* @string: the string to insert
|
||||
* @string: (transfer full): the string to insert
|
||||
*
|
||||
* Adds @string to self at the end, and takes
|
||||
* ownership of it.
|
||||
@@ -587,10 +583,10 @@ gtk_string_list_remove (GtkStringList *self,
|
||||
/**
|
||||
* gtk_string_list_get_string:
|
||||
* @self: a #GtkStringList
|
||||
* @position:
|
||||
* @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().
|
||||
|
||||
+13
-14
@@ -45,30 +45,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
|
||||
|
||||
|
||||
+4
-3
@@ -205,8 +205,6 @@ gtk_switch_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
if (!gtk_widget_compute_bounds (GTK_WIDGET (self), GTK_WIDGET (self), &switch_bounds))
|
||||
return;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
/* If the press didn't happen in the draggable handle,
|
||||
* cancel the pan gesture right away
|
||||
*/
|
||||
@@ -228,7 +226,10 @@ gtk_switch_click_gesture_released (GtkGestureClick *gesture,
|
||||
|
||||
if (gtk_widget_contains (GTK_WIDGET (self), x, y) &&
|
||||
gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
|
||||
gtk_switch_begin_toggle_animation (self);
|
||||
{
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
gtk_switch_begin_toggle_animation (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+29
-10
@@ -1870,6 +1870,7 @@ gtk_text_init (GtkText *self)
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (priv->drag_gesture));
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
gtk_event_controller_set_name (GTK_EVENT_CONTROLLER (gesture), "gtk-text-click-gesture");
|
||||
g_signal_connect (gesture, "pressed",
|
||||
G_CALLBACK (gtk_text_click_gesture_pressed), self);
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
|
||||
@@ -1877,11 +1878,14 @@ gtk_text_init (GtkText *self)
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
|
||||
controller = gtk_event_controller_motion_new ();
|
||||
gtk_event_controller_set_name (controller, "gtk-text-motion-controller");
|
||||
g_signal_connect (controller, "motion",
|
||||
G_CALLBACK (gtk_text_motion_controller_motion), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
priv->key_controller = gtk_event_controller_key_new ();
|
||||
gtk_event_controller_set_propagation_phase (priv->key_controller, GTK_PHASE_TARGET);
|
||||
gtk_event_controller_set_name (priv->key_controller, "gtk-text-key-controller");
|
||||
g_signal_connect (priv->key_controller, "key-pressed",
|
||||
G_CALLBACK (gtk_text_key_controller_key_pressed), self);
|
||||
g_signal_connect_swapped (priv->key_controller, "im-update",
|
||||
@@ -1889,7 +1893,9 @@ gtk_text_init (GtkText *self)
|
||||
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
|
||||
priv->im_context);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), priv->key_controller);
|
||||
|
||||
controller = gtk_event_controller_focus_new ();
|
||||
gtk_event_controller_set_name (controller, "gtk-text-focus-controller");
|
||||
g_signal_connect_swapped (controller, "enter",
|
||||
G_CALLBACK (gtk_text_focus_in), self);
|
||||
g_signal_connect_swapped (controller, "leave",
|
||||
@@ -2621,6 +2627,7 @@ gtk_text_do_popup (GtkText *self,
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
gtk_text_update_clipboard_actions (self);
|
||||
gtk_text_update_emoji_action (self);
|
||||
|
||||
if (!priv->popup_menu)
|
||||
{
|
||||
@@ -2667,8 +2674,6 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), current);
|
||||
|
||||
gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), current,
|
||||
GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
gesture_get_current_point_in_layout (GTK_GESTURE_SINGLE (gesture), self, &x, &y);
|
||||
gtk_text_reset_blink_time (self);
|
||||
|
||||
@@ -2816,12 +2821,13 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
gtk_text_set_positions (self, end, start);
|
||||
}
|
||||
|
||||
gtk_gesture_set_state (priv->drag_gesture,
|
||||
GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
gtk_text_update_handles (self);
|
||||
}
|
||||
|
||||
if (button != GDK_BUTTON_PRIMARY || n_press >= 3)
|
||||
gtk_gesture_set_state (priv->drag_gesture, GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
if (n_press >= 3)
|
||||
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
@@ -3188,11 +3194,15 @@ gtk_text_grab_focus (GtkWidget *widget)
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
gboolean select_on_focus;
|
||||
GtkWidget *prev_focus;
|
||||
|
||||
prev_focus = gtk_root_get_focus (gtk_widget_get_root (widget));
|
||||
|
||||
if (!GTK_WIDGET_CLASS (gtk_text_parent_class)->grab_focus (GTK_WIDGET (self)))
|
||||
return FALSE;
|
||||
|
||||
if (priv->editable && !priv->in_click)
|
||||
if (priv->editable && !priv->in_click &&
|
||||
!(prev_focus && gtk_widget_is_ancestor (prev_focus, widget)))
|
||||
{
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-entry-select-on-focus",
|
||||
@@ -4015,7 +4025,11 @@ gtk_text_copy_clipboard (GtkText *self)
|
||||
return;
|
||||
}
|
||||
|
||||
str = gtk_text_get_display_text (self, priv->selection_bound, priv->current_pos);
|
||||
if (priv->selection_bound < priv->current_pos)
|
||||
str = gtk_text_get_display_text (self, priv->selection_bound, priv->current_pos);
|
||||
else
|
||||
str = gtk_text_get_display_text (self, priv->current_pos, priv->selection_bound);
|
||||
|
||||
gdk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (self)), str);
|
||||
g_free (str);
|
||||
}
|
||||
@@ -4349,6 +4363,8 @@ gtk_text_create_layout (GtkText *self,
|
||||
|
||||
tmp_attrs = gtk_css_style_get_pango_attributes (gtk_css_node_get_style (gtk_widget_get_css_node (widget)));
|
||||
tmp_attrs = _gtk_pango_attr_list_merge (tmp_attrs, priv->attrs);
|
||||
if (!tmp_attrs)
|
||||
tmp_attrs = pango_attr_list_new ();
|
||||
|
||||
display_text = gtk_text_get_display_text (self, 0, -1);
|
||||
|
||||
@@ -4369,10 +4385,7 @@ gtk_text_create_layout (GtkText *self,
|
||||
pos = g_utf8_offset_to_pointer (display_text, priv->current_pos) - display_text;
|
||||
g_string_insert (tmp_string, pos, preedit_string);
|
||||
pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
|
||||
if (tmp_attrs)
|
||||
pango_attr_list_splice (tmp_attrs, preedit_attrs, pos, preedit_length);
|
||||
else
|
||||
tmp_attrs = pango_attr_list_ref (preedit_attrs);
|
||||
pango_attr_list_splice (tmp_attrs, preedit_attrs, pos, preedit_length);
|
||||
g_string_free (tmp_string, TRUE);
|
||||
}
|
||||
else
|
||||
@@ -5389,6 +5402,9 @@ gtk_text_set_editable (GtkText *self,
|
||||
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
|
||||
is_editable ? priv->im_context : NULL);
|
||||
|
||||
gtk_text_update_clipboard_actions (self);
|
||||
gtk_text_update_emoji_action (self);
|
||||
|
||||
g_object_notify (G_OBJECT (self), "editable");
|
||||
}
|
||||
}
|
||||
@@ -5901,7 +5917,10 @@ gtk_text_update_clipboard_actions (GtkText *self)
|
||||
static void
|
||||
gtk_text_update_emoji_action (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
gtk_widget_action_set_enabled (GTK_WIDGET (self), "misc.insert-emoji",
|
||||
priv->editable &&
|
||||
(gtk_text_get_input_hints (self) & GTK_INPUT_HINT_NO_EMOJI) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkAdjustment GtkAdjustment;
|
||||
typedef struct _GtkBitset GtkBitset;
|
||||
typedef struct _GtkBuilder GtkBuilder;
|
||||
typedef struct _GtkBuilderScope GtkBuilderScope;
|
||||
typedef struct _GtkClipboard GtkClipboard;
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* Copyright © 2020 Benjamin Otte
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifndef GTK_VECTOR_TYPE_NAME
|
||||
#define GTK_VECTOR_TYPE_NAME GtkVector
|
||||
#endif
|
||||
|
||||
#ifndef GTK_VECTOR_NAME
|
||||
#define GTK_VECTOR_NAME gtk_vector
|
||||
#endif
|
||||
|
||||
#ifndef GTK_VECTOR_ELEMENT_TYPE
|
||||
#define GTK_VECTOR_ELEMENT_TYPE gpointer
|
||||
#endif
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
#if GTK_VECTOR_PREALLOC == 0
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
#define GTK_VECTOR_REAL_SIZE(_size) ((_size) + 1)
|
||||
#else
|
||||
#define GTK_VECTOR_REAL_SIZE(_size) (_size)
|
||||
#endif
|
||||
|
||||
/* make this readable */
|
||||
#define _T_ GTK_VECTOR_ELEMENT_TYPE
|
||||
#define GtkVector GTK_VECTOR_TYPE_NAME
|
||||
#define gtk_vector_paste_more(GTK_VECTOR_NAME, func_name) GTK_VECTOR_NAME ## _ ## func_name
|
||||
#define gtk_vector_paste(GTK_VECTOR_NAME, func_name) gtk_vector_paste_more (GTK_VECTOR_NAME, func_name)
|
||||
#define gtk_vector(func_name) gtk_vector_paste (GTK_VECTOR_NAME, func_name)
|
||||
|
||||
typedef struct GtkVector GtkVector;
|
||||
|
||||
struct GtkVector
|
||||
{
|
||||
_T_ *start;
|
||||
_T_ *end;
|
||||
_T_ *end_allocation;
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
_T_ preallocated[GTK_VECTOR_REAL_SIZE(GTK_VECTOR_PREALLOC)];
|
||||
#endif
|
||||
};
|
||||
|
||||
/* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */
|
||||
static inline void
|
||||
gtk_vector(init) (GtkVector *self)
|
||||
{
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
self->start = self->preallocated;
|
||||
self->end = self->start;
|
||||
self->end_allocation = self->start + GTK_VECTOR_PREALLOC;
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
*self->start = *(_T_[1]) {};
|
||||
#endif
|
||||
#else
|
||||
self->start = NULL;
|
||||
self->end = NULL;
|
||||
self->end_allocation = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
gtk_vector(free_elements) (_T_ *start,
|
||||
_T_ *end)
|
||||
{
|
||||
#ifdef GTK_VECTOR_FREE_FUNC
|
||||
_T_ *e;
|
||||
for (e = start; e < end; e++)
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
GTK_VECTOR_FREE_FUNC (e);
|
||||
#else
|
||||
GTK_VECTOR_FREE_FUNC (*e);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* no G_GNUC_UNUSED here */
|
||||
static inline void
|
||||
gtk_vector(clear) (GtkVector *self)
|
||||
{
|
||||
gtk_vector(free_elements) (self->start, self->end);
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
if (self->start != self->preallocated)
|
||||
g_free (self->start);
|
||||
#endif
|
||||
gtk_vector(init) (self);
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gtk_vector(get_data) (const GtkVector *self)
|
||||
{
|
||||
return self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline _T_ *
|
||||
gtk_vector(index) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return self->start + pos;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gtk_vector(get_capacity) (const GtkVector *self)
|
||||
{
|
||||
return self->end_allocation - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gsize
|
||||
gtk_vector(get_size) (const GtkVector *self)
|
||||
{
|
||||
return self->end - self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static inline gboolean
|
||||
gtk_vector(is_empty) (const GtkVector *self)
|
||||
{
|
||||
return self->end == self->start;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(reserve) (GtkVector *self,
|
||||
gsize n)
|
||||
{
|
||||
gsize new_size, size;
|
||||
|
||||
if (n <= gtk_vector(get_capacity) (self))
|
||||
return;
|
||||
|
||||
size = gtk_vector(get_size) (self);
|
||||
new_size = 1 << g_bit_storage (MAX (n, 16) - 1);
|
||||
|
||||
#ifdef GTK_VECTOR_PREALLOC
|
||||
if (self->start == self->preallocated)
|
||||
{
|
||||
self->start = g_new (_T_, new_size);
|
||||
memcpy (self->start, self->preallocated, sizeof (_T_) * GTK_VECTOR_REAL_SIZE (size));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef GTK_VECTOR_NULL_TERMINATED
|
||||
if (self->start == NULL)
|
||||
{
|
||||
self->start = g_new (_T_, new_size);
|
||||
*self->start = *(_T_[1]) {};
|
||||
}
|
||||
else
|
||||
#endif
|
||||
self->start = g_renew (_T_, self->start, new_size);
|
||||
|
||||
self->end = self->start + size;
|
||||
self->end_allocation = self->start + new_size;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(splice) (GtkVector *self,
|
||||
gsize pos,
|
||||
gsize removed,
|
||||
_T_ *additions,
|
||||
gsize added)
|
||||
{
|
||||
gsize size;
|
||||
gsize remaining;
|
||||
|
||||
size = gtk_vector(get_size) (self);
|
||||
g_assert (pos + removed <= size);
|
||||
remaining = size - pos - removed;
|
||||
|
||||
gtk_vector(free_elements) (gtk_vector(index) (self, pos),
|
||||
gtk_vector(index) (self, pos + removed));
|
||||
|
||||
gtk_vector(reserve) (self, size - removed + added);
|
||||
|
||||
if (GTK_VECTOR_REAL_SIZE (remaining) && removed != added)
|
||||
memmove (gtk_vector(index) (self, pos + added),
|
||||
gtk_vector(index) (self, pos + removed),
|
||||
GTK_VECTOR_REAL_SIZE (remaining) * sizeof (_T_));
|
||||
|
||||
if (added)
|
||||
{
|
||||
if (additions)
|
||||
memcpy (gtk_vector(index) (self, pos),
|
||||
additions,
|
||||
added * sizeof (_T_));
|
||||
else
|
||||
memset (gtk_vector(index) (self, pos), 0, added * sizeof (_T_));
|
||||
}
|
||||
|
||||
/* might overflow, but does the right thing */
|
||||
self->end += added - removed;
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(set_size) (GtkVector *self,
|
||||
gsize new_size)
|
||||
{
|
||||
gsize old_size = gtk_vector(get_size) (self);
|
||||
if (new_size > old_size)
|
||||
gtk_vector(splice) (self, old_size, 0, NULL, new_size - old_size);
|
||||
else
|
||||
gtk_vector(splice) (self, old_size, old_size - new_size, NULL, 0);
|
||||
}
|
||||
|
||||
G_GNUC_UNUSED static void
|
||||
gtk_vector(append) (GtkVector *self,
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
_T_ *value)
|
||||
#else
|
||||
_T_ value)
|
||||
#endif
|
||||
{
|
||||
gtk_vector(splice) (self,
|
||||
gtk_vector(get_size) (self),
|
||||
0,
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
value,
|
||||
#else
|
||||
&value,
|
||||
#endif
|
||||
1);
|
||||
}
|
||||
|
||||
#ifdef GTK_VECTOR_BY_VALUE
|
||||
G_GNUC_UNUSED static _T_ *
|
||||
gtk_vector(get) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return gtk_vector(index) (self, pos);
|
||||
}
|
||||
#else
|
||||
G_GNUC_UNUSED static _T_
|
||||
gtk_vector(get) (const GtkVector *self,
|
||||
gsize pos)
|
||||
{
|
||||
return *gtk_vector(index) (self, pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef GTK_VECTOR_NO_UNDEF
|
||||
|
||||
#undef _T_
|
||||
#undef GtkVector
|
||||
#undef gtk_vector_paste_more
|
||||
#undef gtk_vector_paste
|
||||
#undef gtk_vector
|
||||
#undef GTK_VECTOR_REAL_SIZE
|
||||
|
||||
#undef GTK_VECTOR_BY_VALUE
|
||||
#undef GTK_VECTOR_ELEMENT_TYPE
|
||||
#undef GTK_VECTOR_FREE_FUNC
|
||||
#undef GTK_VECTOR_NAME
|
||||
#undef GTK_VECTOR_NULL_TERMINATED
|
||||
#undef GTK_VECTOR_PREALLOC
|
||||
#undef GTK_VECTOR_TYPE_NAME
|
||||
|
||||
#endif
|
||||
+20
-2
@@ -4371,6 +4371,22 @@ gtk_widget_run_controllers (GtkWidget *widget,
|
||||
is_gesture = GTK_IS_GESTURE (controller);
|
||||
this_handled = gtk_event_controller_handle_event (controller, event, target, x, y);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
if (GTK_DEBUG_CHECK (KEYBINDINGS))
|
||||
{
|
||||
GdkEventType type = gdk_event_get_event_type (event);
|
||||
if (this_handled &&
|
||||
(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE))
|
||||
{
|
||||
g_message ("key %s (keyval %d) handled at widget %s by controller %s",
|
||||
type == GDK_KEY_PRESS ? "press" : "release",
|
||||
gdk_key_event_get_keyval (event),
|
||||
G_OBJECT_TYPE_NAME (widget),
|
||||
gtk_event_controller_get_name (controller));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
handled |= this_handled;
|
||||
|
||||
/* Non-gesture controllers are basically unique entities not meant
|
||||
@@ -7523,9 +7539,11 @@ _gtk_widget_synthesize_crossing (GtkWidget *from,
|
||||
g_return_if_fail (from != NULL || to != NULL);
|
||||
|
||||
crossing.type = GTK_CROSSING_POINTER;
|
||||
crossing.old_target = from;
|
||||
crossing.new_target = to;
|
||||
crossing.mode = mode;
|
||||
crossing.old_target = from;
|
||||
crossing.old_descendent = NULL;
|
||||
crossing.new_target = to;
|
||||
crossing.new_descendent = NULL;
|
||||
|
||||
if (from)
|
||||
{
|
||||
|
||||
@@ -290,10 +290,14 @@
|
||||
<property name="valign">baseline</property>
|
||||
<property name="hexpand">1</property>
|
||||
<signal name="notify::selected" handler="direction_changed"/>
|
||||
<items>
|
||||
<item translatable="yes">Left-to-Right</item>
|
||||
<item translatable="yes">Right-to-Left</item>
|
||||
</items>
|
||||
<property name="model">
|
||||
<object class="GtkStringList">
|
||||
<items>
|
||||
<item translatable="yes">Left-to-Right</item>
|
||||
<item translatable="yes">Right-to-Left</item>
|
||||
</items>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
+4
-3
@@ -134,7 +134,6 @@ gtk_private_sources = files([
|
||||
'gtkscaler.c',
|
||||
'gtksearchengine.c',
|
||||
'gtksearchenginemodel.c',
|
||||
'gtkset.c',
|
||||
'gtksizerequestcache.c',
|
||||
'gtkstyleanimation.c',
|
||||
'gtkstylecascade.c',
|
||||
@@ -161,9 +160,11 @@ gtk_public_sources = files([
|
||||
'gtkappchooserwidget.c',
|
||||
'gtkapplication.c',
|
||||
'gtkapplicationwindow.c',
|
||||
'gtkarraystore.c',
|
||||
'gtkaspectframe.c',
|
||||
'gtkassistant.c',
|
||||
'gtkbinlayout.c',
|
||||
'gtkbitset.c',
|
||||
'gtkbookmarklist.c',
|
||||
'gtkborder.c',
|
||||
'gtkboxlayout.c',
|
||||
@@ -329,7 +330,6 @@ gtk_public_sources = files([
|
||||
'gtkprintsettings.c',
|
||||
'gtkprogressbar.c',
|
||||
'gtkpropertylookuplistmodel.c',
|
||||
'gtkpropertyselection.c',
|
||||
'gtkradiobutton.c',
|
||||
'gtkrange.c',
|
||||
'gtktreerbtree.c',
|
||||
@@ -448,9 +448,11 @@ gtk_public_headers = files([
|
||||
'gtkappchooserwidget.h',
|
||||
'gtkapplication.h',
|
||||
'gtkapplicationwindow.h',
|
||||
'gtkarraystore.h',
|
||||
'gtkaspectframe.h',
|
||||
'gtkassistant.h',
|
||||
'gtkbinlayout.h',
|
||||
'gtkbitset.h',
|
||||
'gtkbookmarklist.h',
|
||||
'gtkborder.h',
|
||||
'gtkbox.h',
|
||||
@@ -606,7 +608,6 @@ gtk_public_headers = files([
|
||||
'gtkprintoperationpreview.h',
|
||||
'gtkprintsettings.h',
|
||||
'gtkprogressbar.h',
|
||||
'gtkpropertyselection.h',
|
||||
'gtkradiobutton.h',
|
||||
'gtkrange.h',
|
||||
'gtkrecentmanager.h',
|
||||
|
||||
+11453
File diff suppressed because it is too large
Load Diff
+7249
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user