Compare commits

..

25 Commits

Author SHA1 Message Date
Matthias Clasen 825b2a4139 wip: benchmarks 2020-07-12 20:54:46 -04:00
Matthias Clasen 8a23649d40 stringlist: Reuse objects
Keep a bitset of positions where the array contains
objects, and check those for reusable objects whenever
we need a new object.

We still keep the low-bit marking of string pointers,
so we can implement g_list_model_get_item without having
to consult the bitset.

In scrolling through the words demo, this keeps the
number of live string objects at ~200.
2020-07-12 20:52:48 -04:00
Matthias Clasen bf367b219b stringlist: Use an array
A version of GtkStringList that uses a GPtrArray
to hold the strings / objects. We avoid a second
array by marking strings using a low bit of the
pointer.
2020-06-30 23:37:21 -04:00
Matthias Clasen 77435d31fa gtk-demo: Use a progressbar in the words demo
This looks better and a bit more polished.
2020-07-01 02:47:50 +02:00
Matthias Clasen 6edb8f096f gtk-demo: No selection in the words demo
This demo is about filtering, not about selection,
so use a GtkNoSelection.
2020-07-01 02:46:05 +02:00
Matthias Clasen c4dfee8860 gtk-demo: Cosmetic fixes for the words demo
Set a window size, and don't put newlines in titles, left align and
ellipsize the label.
2020-07-01 02:46:05 +02:00
Benjamin Otte 8ac1e77c9a demo: Make words listview load async
And add an "Open" button (why are filechooser buttons such a catastrophe
that I can't make them smaller?).
2020-07-01 02:46:05 +02:00
Benjamin Otte 65ceb6c15a stringlist: Call splice() for adding items after construction
This has the benefit of actually allowing NULL to be passed.
2020-07-01 02:46:05 +02:00
Benjamin Otte f70d10f6ac stringlist: Remove n_additions argument from gtk_string_list_splice()
char ** arrays are null-terminated everywhere, so make sure they are in
splice(), too.

Also fix the argument to be a const char * const * like in the
constructor.
2020-07-01 02:46:05 +02:00
Benjamin Otte 0bbd083d79 stringlist: Clarify docs for gtk_string_list_get_string()
Make sure it's obvious that it behaves like g_list_model_get_item() and
returns NULL for pos >= n_items.
2020-07-01 02:46:05 +02:00
Benjamin Otte 102d2986c6 stringlist: Make one constructor call the other
Simplifies code.
2020-07-01 02:46:05 +02:00
Benjamin Otte c74201ca87 filterlistmodel: Look at type of change
This way we can avoid refiltering most of an already filtered list when
the change becomes more strict.
2020-07-01 02:46:05 +02:00
Benjamin Otte b09019a5b4 gtk-demo: Add incremental filtering to words demo 2020-07-01 02:46:05 +02:00
Benjamin Otte 1dd08ad8db filterlistmodel: Add gtk_filter_list_model_get_pending()
This allows tracking if the model is busy filtering.
2020-07-01 02:46:05 +02:00
Benjamin Otte eb0704855f filterlistmodel: Add incremental filtering 2020-07-01 02:46:05 +02:00
Benjamin Otte c4c1d4a1b3 bitset: Add gtk_bitset_new_range()
It's a common use.
2020-07-01 02:46:05 +02:00
Benjamin Otte e6756f605e stringlist: Make property not construct-only
Massively speeds up creation of long stringlists.
2020-07-01 02:46:05 +02:00
Benjamin Otte 1f4b8e089e filterlistmodel: Rewrite with bitset data structure
Bitsets are more powerful, less memory intensive and faster than the old
GtkRbTree version.
2020-07-01 02:46:05 +02:00
Benjamin Otte c0e08db739 bitset: Add APIs needed for a filterlistmodel 2020-06-30 00:46:56 +02:00
Benjamin Otte 1c337d350d tests: Make testlistview be a list again
The grid conversion was for testing and should never have been
committed.
2020-06-30 00:46:56 +02:00
Benjamin Otte 81e675dfbf gtk-demo: Add a listview demo for filtering strings 2020-06-30 00:36:14 +02:00
Benjamin Otte 8556221429 stringlist: Take a const char const * argument
Sucks that we need to cast a char**, but otherwise we need to cast
{"foo", "bar", "baz" } arrays.
2020-06-30 00:36:14 +02:00
Benjamin Otte 1b4109a7fd scrolledwindow: Expand by default
Use gtk_scrolled_window_set_hexpand/vexpand(FALSE) to make the scrolled
window not expand.
2020-06-30 00:36:13 +02:00
Benjamin Otte df0786be7a stringfilter: Don't crash if the expression returns "" 2020-06-30 00:36:13 +02:00
Benjamin Otte 3f545da08d a11y: Remove double initialization of variables 2020-06-30 00:36:13 +02:00
124 changed files with 5042 additions and 6873 deletions
@@ -9,6 +9,7 @@
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
+1 -1
View File
@@ -140,7 +140,6 @@
</gresource>
<gresource prefix="/listview_colors">
<file compressed="true">color.names.txt</file>
<file>listview_colors.css</file>
</gresource>
<gresource prefix="/shortcuts">
<file>shortcuts.ui</file>
@@ -226,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>
+1 -1
View File
@@ -92,7 +92,7 @@ strings_setup_item_full (GtkSignalListItemFactory *factory,
gtk_label_set_xalign (GTK_LABEL (title), 0.0);
description = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (description), 0.0);
gtk_widget_add_css_class (description, "dim-label");
gtk_style_context_add_class (gtk_widget_get_style_context (description), "dim-label");
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
+1
View File
@@ -7,6 +7,7 @@
<property name="title">Font Explorer</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton" id="reset">
<property name="receives-default">1</property>
+1
View File
@@ -30,6 +30,7 @@ do_headerbar (GtkWidget *do_widget)
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
button = gtk_button_new ();
icon = g_themed_icon_new ("mail-send-receive-symbolic");
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">500</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkBox">
<style>
+2 -146
View File
@@ -627,23 +627,6 @@ setup_listitem_cb (GtkListItemFactory *factory,
gtk_expression_unref (color_expression);
}
static void
setup_selection_listitem_cb (GtkListItemFactory *factory,
GtkListItem *list_item)
{
GtkWidget *picture;
GtkExpression *color_expression, *expression;
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
picture = gtk_picture_new ();
gtk_widget_set_size_request (picture, 8, 8);
gtk_expression_bind (color_expression, picture, "paintable", NULL);
gtk_list_item_set_child (list_item, picture);
}
static void
set_title (gpointer item,
const char *title)
@@ -794,47 +777,6 @@ bind_number_item (GtkSignalListItemFactory *factory,
g_free (string);
}
static void
update_selection_count (GListModel *model,
guint position,
guint removed,
guint added,
gpointer data)
{
char *text;
text = g_strdup_printf ("%u", g_list_model_get_n_items (model));
gtk_label_set_label (GTK_LABEL (data), text);
g_free (text);
}
static void
update_selection_average (GListModel *model,
guint position,
guint removed,
guint added,
gpointer data)
{
guint n = g_list_model_get_n_items (model);
GdkRGBA c = { 0, 0, 0, 1 };
guint i;
GtkColor *color;
for (i = 0; i < n; i++)
{
color = g_list_model_get_item (model, i);
c.red += color->color.red;
c.green += color->color.green;
c.blue += color->color.blue;
g_object_unref (color);
}
color = gtk_color_new ("", c.red / n, c.green / n, c.blue / n);
gtk_picture_set_paintable (GTK_PICTURE (data), GDK_PAINTABLE (color));
g_object_unref (color);
}
static GtkWidget *window = NULL;
GtkWidget *
@@ -855,26 +797,11 @@ do_listview_colors (GtkWidget *do_widget)
PangoAttrList *attrs;
char *string;
guint len;
GtkWidget *selection_view;
GListModel *selection_filter;
GListModel *no_selection;
GtkWidget *grid;
GtkWidget *selection_size_label;
GtkWidget *selection_average_picture;
GtkWidget *selection_info_toggle;
GtkWidget *selection_info_revealer;
GtkCssProvider *provider;
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/listview_colors/listview_colors.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "Colors");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
@@ -882,85 +809,14 @@ do_listview_colors (GtkWidget *do_widget)
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box);
selection_info_revealer = gtk_revealer_new ();
gtk_box_append (GTK_BOX (box), selection_info_revealer);
grid = gtk_grid_new ();
gtk_revealer_set_child (GTK_REVEALER (selection_info_revealer), grid);
gtk_widget_set_margin_start (grid, 10);
gtk_widget_set_margin_end (grid, 10);
gtk_widget_set_margin_top (grid, 10);
gtk_widget_set_margin_bottom (grid, 10);
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
label = gtk_label_new ("Selection");
gtk_widget_set_hexpand (label, TRUE);
gtk_widget_add_css_class (label, "title-3");
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 5, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Size:"), 0, 2, 1, 1);
selection_size_label = gtk_label_new ("0");
gtk_grid_attach (GTK_GRID (grid), selection_size_label, 1, 2, 1, 1);
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Average:"), 2, 2, 1, 1);
selection_average_picture = gtk_picture_new ();
gtk_widget_set_size_request (selection_average_picture, 32, 32);
gtk_grid_attach (GTK_GRID (grid), selection_average_picture, 3, 2, 1, 1);
label = gtk_label_new ("");
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 4, 2, 1, 1);
sw = gtk_scrolled_window_new ();
gtk_widget_set_hexpand (sw, TRUE);
gtk_grid_attach (GTK_GRID (grid), sw, 0, 1, 5, 1);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_selection_listitem_cb), NULL);
selection_view = gtk_grid_view_new_with_factory (factory);
gtk_widget_add_css_class (selection_view, "compact");
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (selection_view), 200);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), selection_view);
sw = gtk_scrolled_window_new ();
gtk_box_append (GTK_BOX (box), sw);
gtk_window_set_child (GTK_WINDOW (window), sw);
gridview = create_color_grid ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
selection_filter = G_LIST_MODEL (gtk_selection_filter_model_new (GTK_SELECTION_MODEL (model)));
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_count), selection_size_label);
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_average), selection_average_picture);
no_selection = G_LIST_MODEL (gtk_no_selection_new (selection_filter));
gtk_grid_view_set_model (GTK_GRID_VIEW (selection_view), no_selection);
g_object_unref (selection_filter);
g_object_unref (no_selection);
g_object_get (model, "model", &model, NULL);
selection_info_toggle = gtk_toggle_button_new ();
gtk_button_set_icon_name (GTK_BUTTON (selection_info_toggle), "emblem-important-symbolic");
gtk_widget_set_tooltip_text (selection_info_toggle, "Show selection info");
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), selection_info_toggle);
g_object_bind_property (selection_info_toggle, "active",
selection_info_revealer, "reveal-child",
G_BINDING_DEFAULT);
button = gtk_button_new_with_mnemonic ("_Refill");
g_signal_connect (button, "clicked",
G_CALLBACK (refill),
-3
View File
@@ -1,3 +0,0 @@
.view.compact > child {
padding: 1px;
}
+1
View File
@@ -174,6 +174,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="icon-name">go-up-symbolic</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="title" translatable="yes">Minesweeper</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="label">New Game</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">480</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child type="end">
<object class="GtkToggleButton" id="search_button">
<property name="icon-name">system-search-symbolic</property>
+8 -9
View File
@@ -194,8 +194,8 @@ create_weather_model (void)
}
static void
setup_widget (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
setup_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
@@ -218,8 +218,8 @@ setup_widget (GtkSignalListItemFactory *factory,
}
static void
bind_widget (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
bind_widget (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *box, *child;
GtkWeatherInfo *info;
@@ -282,12 +282,11 @@ create_weather_view (void)
{
GtkWidget *listview;
GListModel *model, *selection;
GtkListItemFactory *factory;
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_widget), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_widget), NULL);
listview = gtk_list_view_new_with_factory (factory);
listview = gtk_list_view_new_with_factory (
gtk_functions_list_item_factory_new (setup_widget,
bind_widget,
NULL, NULL));
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
model = create_weather_model ();
+241
View File
@@ -0,0 +1,241 @@
/* Lists/Words
*
* This demo shows filtering a long list - of words.
*
* You should have the file `/usr/share/dict/words` installed for
* this demo to work.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *progress;
const char *factory_text =
"<?xml version='1.0' encoding='UTF-8'?>\n"
"<interface>\n"
" <template class='GtkListItem'>\n"
" <property name='child'>\n"
" <object class='GtkLabel'>\n"
" <property name='ellipsize'>end</property>\n"
" <property name='xalign'>0</property>\n"
" <binding name='label'>\n"
" <lookup name='string' type='GtkStringObject'>\n"
" <lookup name='item'>GtkListItem</lookup>\n"
" </lookup>\n"
" </binding>\n"
" </object>\n"
" </property>\n"
" </template>\n"
"</interface>\n";
static void
update_title_cb (GtkFilterListModel *model)
{
guint total;
char *title;
guint pending;
total = g_list_model_get_n_items (gtk_filter_list_model_get_model (model));
pending = gtk_filter_list_model_get_pending (model);
title = g_strdup_printf ("%u lines", g_list_model_get_n_items (G_LIST_MODEL (model)));
gtk_widget_set_visible (progress, pending != 0);
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (progress), (total - pending) / (double) total);
gtk_window_set_title (GTK_WINDOW (window), title);
g_free (title);
}
static void
read_lines_cb (GObject *object,
GAsyncResult *result,
gpointer data)
{
GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (object);
GtkStringList *stringlist = data;
GError *error = NULL;
gsize size;
GPtrArray *lines;
gssize n_filled;
const char *buffer, *newline;
n_filled = g_buffered_input_stream_fill_finish (stream, result, &error);
if (n_filled < 0)
{
g_print ("Could not read data: %s\n", error->message);
g_clear_error (&error);
return;
}
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
if (n_filled == 0)
{
if (size)
gtk_string_list_take (stringlist, g_utf8_make_valid (buffer, size));
return;
}
lines = NULL;
while ((newline = memchr (buffer, '\n', size)))
{
if (newline > buffer)
{
if (lines == NULL)
lines = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (lines, g_utf8_make_valid (buffer, newline - buffer));
}
if (g_input_stream_skip (G_INPUT_STREAM (stream), newline - buffer + 1, NULL, &error) < 0)
{
g_clear_error (&error);
break;
}
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
}
if (lines == NULL)
{
g_buffered_input_stream_set_buffer_size (stream, g_buffered_input_stream_get_buffer_size (stream) + 4096);
}
else
{
g_ptr_array_add (lines, NULL);
gtk_string_list_splice (stringlist, g_list_model_get_n_items (G_LIST_MODEL (stringlist)), 0, (const char **) lines->pdata);
g_ptr_array_free (lines, TRUE);
}
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
}
static void
file_is_open_cb (GObject *file,
GAsyncResult *result,
gpointer data)
{
GError *error = NULL;
GFileInputStream *file_stream;
GBufferedInputStream *stream;
file_stream = g_file_read_finish (G_FILE (file), result, &error);
if (file_stream == NULL)
{
g_print ("Could not open file: %s\n", error->message);
g_error_free (error);
return;
}
stream = G_BUFFERED_INPUT_STREAM (g_buffered_input_stream_new (G_INPUT_STREAM (file_stream)));
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
g_object_unref (stream);
}
static void
load_file (GtkStringList *list,
GFile *file)
{
gtk_string_list_splice (list, 0, g_list_model_get_n_items (G_LIST_MODEL (list)), NULL);
g_file_read_async (file, G_PRIORITY_HIGH_IDLE, NULL, file_is_open_cb, list);
}
static void
file_selected_cb (GtkWidget *button,
GtkStringList *stringlist)
{
GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (button));
if (file)
{
load_file (stringlist, file);
g_object_unref (file);
}
}
GtkWidget *
do_listview_words (GtkWidget *do_widget)
{
if (window == NULL)
{
GtkWidget *header, *listview, *sw, *vbox, *search_entry, *open_button, *overlay;
GtkFilterListModel *filter_model;
GtkNoSelection *selection;
GtkStringList *stringlist;
GtkFilter *filter;
GtkExpression *expression;
GFile *file;
file = g_file_new_for_path ("/usr/share/dict/words");
if (g_file_query_exists (file, NULL))
{
stringlist = gtk_string_list_new (NULL);
load_file (stringlist, file);
}
else
{
char **words;
words = g_strsplit ("lorem ipsum dolor sit amet consectetur adipisci elit sed eiusmod tempor incidunt labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat", " ", -1);
stringlist = gtk_string_list_new ((const char **) words);
g_strfreev (words);
}
filter = gtk_string_filter_new ();
expression = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string");
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter), expression);
gtk_expression_unref (expression);
filter_model = gtk_filter_list_model_new (G_LIST_MODEL (stringlist), filter);
gtk_filter_list_model_set_incremental (filter_model, TRUE);
window = gtk_window_new ();
gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
open_button = gtk_file_chooser_button_new ("_Open", GTK_FILE_CHOOSER_ACTION_OPEN);
g_signal_connect (open_button, "file-set", G_CALLBACK (file_selected_cb), stringlist);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), open_button);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), vbox);
search_entry = gtk_search_entry_new ();
g_object_bind_property (search_entry, "text", filter, "search", 0);
gtk_box_append (GTK_BOX (vbox), search_entry);
overlay = gtk_overlay_new ();
gtk_box_append (GTK_BOX (vbox), overlay);
progress = gtk_progress_bar_new ();
gtk_widget_set_halign (progress, GTK_ALIGN_FILL);
gtk_widget_set_valign (progress, GTK_ALIGN_START);
gtk_widget_set_hexpand (progress, TRUE);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), progress);
sw = gtk_scrolled_window_new ();
gtk_overlay_set_child (GTK_OVERLAY (overlay), sw);
listview = gtk_list_view_new_with_factory (
gtk_builder_list_item_factory_new_from_bytes (NULL,
g_bytes_new_static (factory_text, strlen (factory_text))));
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
selection = gtk_no_selection_new (G_LIST_MODEL (filter_model));
gtk_list_view_set_model (GTK_LIST_VIEW (listview), G_LIST_MODEL (selection));
g_object_unref (selection);
g_signal_connect (filter_model, "items-changed", G_CALLBACK (update_title_cb), progress);
g_signal_connect (filter_model, "notify::pending", G_CALLBACK (update_title_cb), progress);
update_title_cb (filter_model);
g_object_unref (filter_model);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
+1
View File
@@ -24,6 +24,7 @@
<property name="default-height">600</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkButton">
<property name="valign">center</property>
+1
View File
@@ -69,6 +69,7 @@ do_markup (GtkWidget *do_widget)
g_signal_connect (show_source, "toggled", G_CALLBACK (source_toggled), stack);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), show_source);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
+1
View File
@@ -49,6 +49,7 @@ demos = files([
'listview_minesweeper.c',
'listview_settings.c',
'listview_weather.c',
'listview_words.c',
'markup.c',
'modelbutton.c',
'overlay.c',
+3 -1
View File
@@ -4,7 +4,9 @@
<property name="title" translatable="yes">Model Button</property>
<property name="resizable">0</property>
<child type="titlebar">
<object class="GtkHeaderBar"/>
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
</object>
</child>
<child>
<object class="GtkBox">
+1
View File
@@ -392,6 +392,7 @@ do_paint (GtkWidget *toplevel)
gtk_window_set_child (GTK_WINDOW (window), draw_area);
headerbar = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (headerbar), TRUE);
colorbutton = gtk_color_button_new ();
g_signal_connect (colorbutton, "color-set",
+1
View File
@@ -276,6 +276,7 @@ do_peg_solitaire (GtkWidget *do_widget)
g_signal_connect (restart, "clicked", G_CALLBACK (restart), NULL);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
+1
View File
@@ -40,6 +40,7 @@ do_sidebar (GtkWidget *do_widget)
gtk_widget_set_size_request (window, 500, 350);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR(header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW(window), header);
gtk_window_set_title (GTK_WINDOW(window), "Stack Sidebar");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
+1
View File
@@ -470,6 +470,7 @@ do_sliding_puzzle (GtkWidget *do_widget)
g_signal_connect (restart, "clicked", G_CALLBACK (reshuffle), NULL);
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), restart);
gtk_header_bar_pack_end (GTK_HEADER_BAR (header), tweak);
window = gtk_window_new ();
+1
View File
@@ -4,6 +4,7 @@
<property name="resizable">0</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkToggleButton" id="toggle">
<property name="label">Cycle</property>
+1
View File
@@ -73,6 +73,7 @@ do_video_player (GtkWidget *do_widget)
gtk_window_set_child (GTK_WINDOW (window), video);
title = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (title), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), title);
open_button = gtk_button_new_with_mnemonic ("_Open");
+1
View File
@@ -21,6 +21,7 @@
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkBox">
<style>
+1
View File
@@ -103,6 +103,7 @@
<property name="focus-widget">text_view</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
+1
View File
@@ -436,6 +436,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="title">GTK Widget Factory</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar1">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="stack_switcher">
<property name="stack">toplevel_stack</property>
+2
View File
@@ -1423,6 +1423,7 @@ the search bar below the header bar.
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
@@ -1536,6 +1537,7 @@ GtkMenuButton, GtkRevealer and GtkListBox.
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
-1
View File
@@ -74,7 +74,6 @@
<xi:include href="xml/gtksingleselection.xml" />
<xi:include href="xml/gtkmultiselection.xml" />
</section>
<xi:include href="xml/gtkselectionfiltermodel.xml" />
<xi:include href="xml/gtkbookmarklist.xml" />
<xi:include href="xml/gtkdirectorylist.xml" />
<xi:include href="xml/gtkstringlist.xml" />
+4 -11
View File
@@ -348,6 +348,7 @@ GtkBitset
gtk_bitset_ref
gtk_bitset_unref
gtk_bitset_new_empty
gtk_bitset_new_range
gtk_bitset_copy
<SUBSECTION>
gtk_bitset_contains
@@ -449,7 +450,6 @@ gtk_single_selection_get_type
<TITLE>GtkMultiSeledction</TITLE>
GtkMultiSelection
gtk_multi_selection_new
gtk_multi_selection_get_model
<SUBSECTION Private>
gtk_multi_selection_get_type
</SECTION>
@@ -1544,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
@@ -7613,13 +7616,3 @@ gtk_string_list_get_string
GtkStringObject
gtk_string_object_get_string
</SECTION>
<SECTION>
<FILE>gtkselectionfiltermodel</FILE>
<TITLE>GtkSelectionFilterModel</TITLE>
GtkSelectionFilterModel
gtk_selection_filter_model_new
gtk_selection_filter_model_new_for_type
gtk_selection_filter_model_set_model
gtk_selection_filter_model_get_model
</SECTION>
-1
View File
@@ -184,7 +184,6 @@ gtk_scrollbar_get_type
gtk_scrolled_window_get_type
gtk_search_bar_get_type
gtk_search_entry_get_type
gtk_selection_filter_model_get_type
gtk_selection_model_get_type
gtk_separator_get_type
gtk_settings_get_type
-1
View File
@@ -411,7 +411,6 @@ and gtk_box_append(). You can also reorder box children as necessary.
The gtk_header_bar_set_show_close_button() function has been renamed to
the more accurate name gtk_header_bar_set_show_title_buttons(). The
corresponding getter and the property itself have also been renamed.
The default value of the property is now %TRUE instead of %FALSE.
The gtk_header_bar_set_custom_title() function has been renamed to
the more accurate name gtk_header_bar_set_title_widget(). The
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="tabs">
<property name="stack">stack</property>
+1
View File
@@ -6,6 +6,7 @@
<property name="default-height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkLabel" id="lines_label">
<property name="visible">0</property>
+1
View File
@@ -15,6 +15,7 @@ new_window (GApplication *app,
gtk_window_set_icon_name (GTK_WINDOW (window), "sunny");
header = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
overlay = gtk_overlay_new ();
+1 -1
View File
@@ -1184,7 +1184,7 @@ _gdk_wm_protocols_filter (const XEvent *xevent,
if (timings)
timings->drawn_time = frame_drawn_time;
if (!surface_impl->toplevel->frame_still_painting && surface_impl->toplevel->frame_pending)
if (surface_impl->toplevel->frame_pending)
{
surface_impl->toplevel->frame_pending = FALSE;
gdk_surface_thaw_updates (win);
+10 -49
View File
@@ -582,23 +582,6 @@ create_legacy_context (GdkDisplay *display,
}
#ifdef HAVE_XDAMAGE
static void
finish_frame (GdkGLContext *context)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
if (context_x11->xdamage == 0)
return;
if (context_x11->frame_fence == 0)
return;
glDeleteSync (context_x11->frame_fence);
context_x11->frame_fence = 0;
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
}
static void
bind_context_for_frame_fence (GdkGLContext *context)
{
@@ -645,6 +628,7 @@ on_gl_surface_xevent (GdkGLContext *context,
GdkX11Display *display_x11)
{
GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
GdkSurface *surface = gdk_gl_context_get_surface (context);
XDamageNotifyEvent *damage_xevent;
if (!context_x11->is_attached)
@@ -691,7 +675,9 @@ on_gl_surface_xevent (GdkGLContext *context,
case GL_WAIT_FAILED:
if (wait_result == GL_WAIT_FAILED)
g_warning ("failed to wait on GL fence associated with last swap buffers call");
finish_frame (context);
glDeleteSync (context_x11->frame_fence);
context_x11->frame_fence = 0;
_gdk_x11_surface_set_frame_still_painting (surface, FALSE);
break;
/* We assume that if the fence hasn't been signaled, that this
@@ -710,21 +696,6 @@ on_gl_surface_xevent (GdkGLContext *context,
return FALSE;
}
static void
on_surface_state_changed (GdkGLContext *context)
{
GdkSurface *surface = gdk_gl_context_get_surface (context);
if ((surface->state & GDK_SURFACE_STATE_WITHDRAWN) == 0)
return;
/* If we're about to withdraw the surface, then we don't care if the frame is
* still getting rendered by the GPU. The compositor is going to remove the surface
* from the scene anyway, so wrap up the frame.
*/
finish_frame (context);
}
#endif
static gboolean
@@ -907,23 +878,13 @@ gdk_x11_gl_context_realize (GdkGLContext *context,
gdk_x11_surface_get_xid (surface),
XDamageReportRawRectangles);
if (gdk_x11_display_error_trap_pop (display))
{
context_x11->xdamage = 0;
}
context_x11->xdamage = 0;
else
{
g_signal_connect_object (G_OBJECT (display),
"xevent",
G_CALLBACK (on_gl_surface_xevent),
context,
G_CONNECT_SWAPPED);
g_signal_connect_object (G_OBJECT (surface),
"notify::state",
G_CALLBACK (on_surface_state_changed),
context,
G_CONNECT_SWAPPED);
}
g_signal_connect_object (G_OBJECT (display),
"xevent",
G_CALLBACK (on_gl_surface_xevent),
context,
G_CONNECT_SWAPPED);
}
#endif
+6 -16
View File
@@ -2241,23 +2241,12 @@ render_cross_fade_node (GskGLRenderer *self,
{
GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node);
GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node);
const float progress = gsk_cross_fade_node_get_progress (node);
float progress = gsk_cross_fade_node_get_progress (node);
TextureRegion start_region;
TextureRegion end_region;
gboolean is_offscreen1, is_offscreen2;
OpCrossFade *op;
if (progress <= 0)
{
gsk_gl_renderer_add_render_ops (self, start_node, builder);
return;
}
else if (progress >= 1)
{
gsk_gl_renderer_add_render_ops (self, end_node, builder);
return;
}
/* TODO: We create 2 textures here as big as the cross-fade node, but both the
* start and the end node might be a lot smaller than that. */
@@ -2277,10 +2266,11 @@ render_cross_fade_node (GskGLRenderer *self,
&end_region, &is_offscreen2,
FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY))
{
const float prev_opacity = ops_set_opacity (builder, builder->current_opacity * progress);
gsk_gl_renderer_add_render_ops (self, start_node, builder);
ops_set_opacity (builder, prev_opacity);
load_vertex_data_with_region (ops_draw (builder, NULL),
node,
builder,
&start_region,
TRUE);
return;
}
+19 -19
View File
@@ -104,7 +104,7 @@ gsk_color_node_peek_color (GskRenderNode *node)
}
/**
* gsk_color_node_new:
* gsk_color_node_new:
* @rgba: a #GdkRGBA specifying a color
* @bounds: the rectangle to render the color into
*
@@ -216,7 +216,7 @@ gsk_linear_gradient_node_diff (GskRenderNode *node1,
return;
}
gsk_render_node_diff_impossible (node1, node2, region);
}
@@ -1163,7 +1163,7 @@ gsk_inset_shadow_node_diff (GskRenderNode *node1,
}
/**
* gsk_inset_shadow_node_new:
* gsk_inset_shadow_node_new:
* @outline: outline of the region containing the shadow
* @color: color of the shadow
* @dx: horizontal offset of shadow
@@ -1465,7 +1465,7 @@ gsk_outset_shadow_node_diff (GskRenderNode *node1,
}
/**
* gsk_outset_shadow_node_new:
* gsk_outset_shadow_node_new:
* @outline: outline of the region surrounded by shadow
* @color: color of the shadow
* @dx: horizontal offset of shadow
@@ -1672,7 +1672,7 @@ gsk_cairo_node_peek_surface (GskRenderNode *node)
}
/**
* gsk_cairo_node_new:
* gsk_cairo_node_new:
* @bounds: the rectangle to render to
*
* Creates a #GskRenderNode that will render a cairo surface
@@ -1982,7 +1982,7 @@ gsk_transform_node_draw (GskRenderNode *node,
ctm.xy, ctm.yy,
ctm.x0, ctm.y0));
cairo_transform (cr, &ctm);
gsk_render_node_draw (self->child, cr);
}
@@ -2062,7 +2062,7 @@ gsk_transform_node_diff (GskRenderNode *node1,
}
/**
* gsk_transform_node_new:
* gsk_transform_node_new:
* @child: The node to transform
* @transform: (transfer none): The transform to apply
*
@@ -2188,7 +2188,7 @@ gsk_opacity_node_diff (GskRenderNode *node1,
}
/**
* gsk_opacity_node_new:
* gsk_opacity_node_new:
* @child: The node to draw
* @opacity: The opacity to apply
*
@@ -2380,7 +2380,7 @@ nope:
}
/**
* gsk_color_matrix_node_new:
* gsk_color_matrix_node_new:
* @child: The node to draw
* @color_matrix: The matrix to apply
* @color_offset: Values to add to the color
@@ -2533,7 +2533,7 @@ gsk_repeat_node_draw (GskRenderNode *node,
}
/**
* gsk_repeat_node_new:
* gsk_repeat_node_new:
* @bounds: The bounds of the area to be painted
* @child: The child to repeat
* @child_bounds: (allow-none): The area of the child to repeat or %NULL to
@@ -2670,7 +2670,7 @@ gsk_clip_node_diff (GskRenderNode *node1,
}
/**
* gsk_clip_node_new:
* gsk_clip_node_new:
* @child: The node to draw
* @clip: The clip to apply
*
@@ -2800,7 +2800,7 @@ gsk_rounded_clip_node_diff (GskRenderNode *node1,
}
/**
* gsk_rounded_clip_node_new:
* gsk_rounded_clip_node_new:
* @child: The node to draw
* @clip: The clip to apply
*
@@ -3013,7 +3013,7 @@ gsk_shadow_node_get_bounds (GskShadowNode *self,
}
/**
* gsk_shadow_node_new:
* gsk_shadow_node_new:
* @child: The node to draw
* @shadows: (array length=n_shadows): The shadows to apply
* @n_shadows: number of entries in the @shadows array
@@ -3210,7 +3210,7 @@ gsk_blend_node_diff (GskRenderNode *node1,
}
/**
* gsk_blend_node_new:
* gsk_blend_node_new:
* @bottom: The bottom node to be drawn
* @top: The node to be blended onto the @bottom node
* @blend_mode: The blend mode to use
@@ -3359,7 +3359,7 @@ gsk_cross_fade_node_diff (GskRenderNode *node1,
}
/**
* gsk_cross_fade_node_new:
* gsk_cross_fade_node_new:
* @start: The start node to be drawn
* @end: The node to be cross_fadeed onto the @start node
* @progress: How far the fade has progressed from start to end. The value will
@@ -3549,7 +3549,7 @@ font_has_color_glyphs (const PangoFont *font)
}
/**
* gsk_text_node_new:
* gsk_text_node_new:
* @font: the #PangoFont containing the glyphs
* @glyphs: the #PangoGlyphString to render
* @color: the foreground color to render with
@@ -3953,7 +3953,7 @@ gsk_blur_node_diff (GskRenderNode *node1,
}
/**
* gsk_blur_node_new:
* gsk_blur_node_new:
* @child: the child node to blur
* @radius: the blur radius
*
@@ -4076,9 +4076,9 @@ gsk_debug_node_diff (GskRenderNode *node1,
}
/**
* gsk_debug_node_new:
* gsk_debug_node_new:
* @child: The child to add debug info for
* @message: (transfer full): The debug message
* @message: (transfer full): The debug message
*
* Creates a #GskRenderNode that will add debug information about
* the given @child.
-1
View File
@@ -295,7 +295,6 @@ gtk_cell_accessible_action_do_action (AtkAction *action,
GtkCellAccessible *cell = GTK_CELL_ACCESSIBLE (action);
GtkCellAccessibleParent *parent;
cell = GTK_CELL_ACCESSIBLE (action);
if (gtk_accessible_get_widget (GTK_ACCESSIBLE (cell)) == NULL)
return FALSE;
+1 -1
View File
@@ -65,7 +65,7 @@ static gunichar
gtk_password_entry_accessible_get_character_at_offset (AtkText *atk_text,
gint offset)
{
GtkText *text = get_text_widget (GTK_ACCESSIBLE (atk_text));
GtkText *text;
char *contents, *index;
gunichar result;
+1 -1
View File
@@ -133,6 +133,7 @@
#include <gtk/gtkfontchooserdialog.h>
#include <gtk/gtkfontchooserwidget.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkfunctionslistitemfactory.h>
#include <gtk/gtkgesture.h>
#include <gtk/gtkgestureclick.h>
#include <gtk/gtkgesturedrag.h>
@@ -213,7 +214,6 @@
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtksearchbar.h>
#include <gtk/gtksearchentry.h>
#include <gtk/gtkselectionfiltermodel.h>
#include <gtk/gtkselectionmodel.h>
#include <gtk/gtkseparator.h>
#include <gtk/gtksettings.h>
+23 -1
View File
@@ -268,7 +268,7 @@ gtk_bitset_get_nth (const GtkBitset *self,
*
* Creates a new empty bitset.
*
* Returns: A new empty bitset.
* Returns: A new empty bitset
**/
GtkBitset *
gtk_bitset_new_empty (void)
@@ -284,6 +284,28 @@ gtk_bitset_new_empty (void)
return self;
}
/**
* gtk_bitset_new_range:
* @start: first value to add
* @n_items: number of consecutive values to add
*
* Creates a bitset with the given range set.
*
* Returns: A new bitset
**/
GtkBitset *
gtk_bitset_new_range (guint start,
guint n_items)
{
GtkBitset *self;
self = gtk_bitset_new_empty ();
gtk_bitset_add_range (self, start, n_items);
return self;
}
/**
* gtk_bitset_copy:
* @self: a #GtkBitset
+3
View File
@@ -65,6 +65,9 @@ GDK_AVAILABLE_IN_ALL
GtkBitset * gtk_bitset_new_empty (void);
GDK_AVAILABLE_IN_ALL
GtkBitset * gtk_bitset_copy (const GtkBitset *self);
GDK_AVAILABLE_IN_ALL
GtkBitset * gtk_bitset_new_range (guint start,
guint n_items);
GDK_AVAILABLE_IN_ALL
void gtk_bitset_remove_all (GtkBitset *self);
+1 -1
View File
@@ -29,7 +29,7 @@
/**
* SECTION:gtkbuilderlistitemfactory
* @Title: GtkBuilderListItemFactory
* @Tiitle: GtkBuilderListItemFactory
* @Short_description: A listitem factory using ui files
*
* #GtkBuilderListItemFactory is a #GtkListItemFactory that creates
+2 -2
View File
@@ -940,7 +940,7 @@ header_drag_end (GtkGestureDrag *gesture,
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
header = gtk_column_view_column_get_header (column);
gtk_widget_remove_css_class (header, "dnd");
gtk_style_context_remove_class (gtk_widget_get_style_context (header), "dnd");
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
@@ -1027,7 +1027,7 @@ header_drag_update (GtkGestureDrag *gesture,
header = gtk_column_view_column_get_header (column);
gtk_widget_insert_after (header, self->header, gtk_widget_get_last_child (self->header));
gtk_widget_add_css_class (header, "dnd");
gtk_style_context_add_class (gtk_widget_get_style_context (header), "dnd");
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
if (!gtk_widget_has_focus (GTK_WIDGET (self)))
+1 -1
View File
@@ -943,7 +943,7 @@ gtk_drop_down_set_from_strings (GtkDropDown *self,
set_default_factory (self);
model = G_LIST_MODEL (gtk_string_list_new ((const char **)texts));
model = G_LIST_MODEL (gtk_string_list_new (texts));
gtk_drop_down_set_model (self, model);
g_object_unref (model);
}
+11 -44
View File
@@ -1,4 +1,3 @@
/*
* Copyright © 2019 Benjamin Otte
*
@@ -29,50 +28,18 @@
* @Short_description: Expressions to values
* @Title: GtkExpression
*
* GtkExpression provides a way to describe references to values.
* GtkExpression provides a way to describe references to #GValues.
*
* An important aspect of expressions is that the value can be obtained
* from a source that is several steps away. For example, an expression
* may describe the value of property A of @object1, which is itself the
* value of a property of @object2. And @object1 may not even exist yet
* at the time that the expression is created. This is contrast to GObject
* property bindings, which can only create direct connections between
* the properties of two objects that must both exist for the duration
* of the binding.
*
* An expression needs to be "evaluated" to obtain the value that it currently
* refers to. An evaluation always happens in the context of a current object
* called `this` (it mirrors the behavior of object-oriented languages),
* which may or may not influence the result of the evaluation. Use
* gtk_expression_evaluate() for evaluating an expression.
* An expression needs to be "evaluated" to obtain the value that it currently refers
* to. An evaluation always happens in the context of a current object called `this`
* (it mirrors the behavior of object-oriented languages), which may or may not
* influence the result of the evaluation. Use gtk_expression_evaluate() for
* evaluating an expression.
*
* Various methods for defining expressions exist, from simple constants via
* gtk_constant_expression_new() to looking up properties in a #GObject (even
* recursively) via gtk_property_expression_new() or providing custom functions
* to transform and combine expressions via gtk_closure_expression_new().
*
* Here is an example of a complex expression:
* |[
* color_expr = gtk_property_expression_new (GTK_TYPE_LIST_ITEM,
* NULL, "item");
* expression = gtk_property_expression_new (GTK_TYPE_COLOR,
* color_expr,
* "name");
* ]|
* when evaluated with `this` being a GtkListItem, it will obtain the
* "item" property from the GtkListItem, and then obtain the "name" property
* from the resulting object (which is assumed to be of type GTK_TYPE_COLOR).
*
* A more concise way to describe this would be
* |[
* this->item->name
* ]|
*
* The most likely place where you will encounter expressions is in the context
* of list models and list widgets using them. For example, #GtkDropDown is
* evaluating a GtkExpression to obtain strings from the items in its model
* that it can then use to match against the contents of its search entry.
* #GtkStringFilter is using a GtkExpression for a similar reason.
* recursively) via gtk_property_expression_new() or providing custom functions to
* transform and combine expressions via gtk_closure_expression_new().
*
* By default, expressions are not paying attention to changes and evaluation is
* just a snapshot of the current state at a given time. To get informed about
@@ -1570,12 +1537,12 @@ GTK_DEFINE_EXPRESSION_TYPE (GtkCClosureExpression,
/**
* gtk_cclosure_expression_new:
* @value_type: the type of the value that this expression evaluates to
* @marshal: (scope call) (nullable): marshaller used for creating a closure
* @marshal: (scope call): marshaller used for creating a closure
* @n_params: the number of params needed for evaluating @closure
* @params: (array length=n_params) (transfer full): expressions for each parameter
* @callback_func: (scope notified) (closure user_data) (destroy user_destroy): callback used for creating a closure
* @user_data: (nullable): user data used for creating a closure
* @user_destroy: (nullable): destroy notify for @user_data
* @user_data: user data used for creating a closure
* @user_destroy: destroy notify for @user_data
*
* This function is a variant of gtk_closure_expression_new() that
* creates a #GClosure by calling gtk_cclosure_new() with the given
+4 -92
View File
@@ -73,7 +73,6 @@
#include "gtkbuilderprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkfilter.h"
typedef struct _GtkFileFilterClass GtkFileFilterClass;
typedef struct _FilterRule FilterRule;
@@ -91,12 +90,12 @@ typedef enum {
struct _GtkFileFilterClass
{
GtkFilterClass parent_class;
GInitiallyUnownedClass parent_class;
};
struct _GtkFileFilter
{
GtkFilter parent_instance;
GInitiallyUnowned parent_instance;
gchar *name;
GSList *rules;
@@ -108,7 +107,7 @@ struct _FilterRule
{
FilterRuleType type;
GtkFileFilterFlags needed;
union {
gchar *pattern;
gchar *mime_type;
@@ -157,12 +156,7 @@ static void gtk_file_filter_buildable_custom_tag_end (GtkBuildable
const gchar *tagname,
gpointer data);
static gboolean gtk_file_filter_match (GtkFilter *filter,
gpointer item);
static GtkFilterMatch gtk_file_filter_get_strictness (GtkFilter *filter);
G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, G_TYPE_OBJECT,
G_DEFINE_TYPE_WITH_CODE (GtkFileFilter, gtk_file_filter, G_TYPE_INITIALLY_UNOWNED,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_file_filter_buildable_init))
@@ -175,15 +169,11 @@ static void
gtk_file_filter_class_init (GtkFileFilterClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkFilterClass *filter_class = GTK_FILTER_CLASS (class);
gobject_class->set_property = gtk_file_filter_set_property;
gobject_class->get_property = gtk_file_filter_get_property;
gobject_class->finalize = gtk_file_filter_finalize;
filter_class->match = gtk_file_filter_match;
filter_class->get_strictness = gtk_file_filter_get_strictness;
/**
* GtkFileFilter:name:
*
@@ -446,84 +436,6 @@ gtk_file_filter_buildable_custom_tag_end (GtkBuildable *buildable,
}
}
/* GtkFilter implementation */
static gboolean
gtk_file_filter_match (GtkFilter *filter,
gpointer item)
{
GtkFileFilter *file_filter = GTK_FILE_FILTER (filter);
GFileInfo *info;
GFile *file;
GtkFileFilterInfo filter_info = { 0, };
GtkFileFilterFlags required;
gboolean result;
char *mime_type = NULL;
char *filename = NULL;
char *uri = NULL;
if (!G_IS_FILE_INFO (item))
return TRUE;
info = G_FILE_INFO (item);
file = G_FILE (g_file_info_get_attribute_object (info, "standard::file"));
required = file_filter->needed;
filter_info.contains = GTK_FILE_FILTER_DISPLAY_NAME;
filter_info.display_name = g_file_info_get_display_name (info);
if (required & GTK_FILE_FILTER_MIME_TYPE)
{
const char *s = g_file_info_get_content_type (info);
if (!s)
s = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE);
if (s)
{
mime_type = g_content_type_get_mime_type (s);
if (mime_type)
{
filter_info.mime_type = mime_type;
filter_info.contains |= GTK_FILE_FILTER_MIME_TYPE;
}
}
}
if (required & GTK_FILE_FILTER_FILENAME)
{
filename = g_file_get_path (file);
if (filename)
{
filter_info.filename = filename;
filter_info.contains |= GTK_FILE_FILTER_FILENAME;
}
}
if (required & GTK_FILE_FILTER_URI)
{
uri = g_file_get_uri (file);
if (uri)
{
filter_info.uri = uri;
filter_info.contains |= GTK_FILE_FILTER_URI;
}
}
result = gtk_file_filter_filter (file_filter, &filter_info);
g_free (mime_type);
g_free (filename);
g_free (uri);
return result;
}
static GtkFilterMatch
gtk_file_filter_get_strictness (GtkFilter *filter)
{
return GTK_FILTER_MATCH_SOME;
}
/**
* gtk_file_filter_new:
+331 -355
View File
@@ -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:
*
@@ -684,7 +608,19 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
P_("Model"),
P_("The model being filtered"),
G_TYPE_LIST_MODEL,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
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);
}
+8
View File
@@ -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
+135
View File
@@ -0,0 +1,135 @@
/*
* Copyright © 2019 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 "gtkfunctionslistitemfactory.h"
#include "gtklistitemfactoryprivate.h"
#include "gtklistitemprivate.h"
struct _GtkFunctionsListItemFactory
{
GtkListItemFactory parent_instance;
GtkListItemSetupFunc setup_func;
GtkListItemBindFunc bind_func;
gpointer user_data;
GDestroyNotify user_destroy;
};
struct _GtkFunctionsListItemFactoryClass
{
GtkListItemFactoryClass parent_class;
};
G_DEFINE_TYPE (GtkFunctionsListItemFactory, gtk_functions_list_item_factory, GTK_TYPE_LIST_ITEM_FACTORY)
static void
gtk_functions_list_item_factory_setup (GtkListItemFactory *factory,
GtkListItemWidget *widget,
GtkListItem *list_item)
{
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (factory);
if (self->setup_func)
self->setup_func (list_item, self->user_data);
GTK_LIST_ITEM_FACTORY_CLASS (gtk_functions_list_item_factory_parent_class)->setup (factory, widget, list_item);
if (gtk_list_item_get_item (list_item) != NULL && self->bind_func)
self->bind_func (list_item, self->user_data);
}
static void
gtk_functions_list_item_factory_update (GtkListItemFactory *factory,
GtkListItemWidget *widget,
GtkListItem *list_item,
guint position,
gpointer item,
gboolean selected)
{
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (factory);
GTK_LIST_ITEM_FACTORY_CLASS (gtk_functions_list_item_factory_parent_class)->update (factory, widget, list_item, position, item, selected);
if (item != NULL && self->bind_func)
self->bind_func (list_item, self->user_data);
}
static void
gtk_functions_list_item_factory_finalize (GObject *object)
{
GtkFunctionsListItemFactory *self = GTK_FUNCTIONS_LIST_ITEM_FACTORY (object);
if (self->user_destroy)
self->user_destroy (self->user_data);
G_OBJECT_CLASS (gtk_functions_list_item_factory_parent_class)->finalize (object);
}
static void
gtk_functions_list_item_factory_class_init (GtkFunctionsListItemFactoryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkListItemFactoryClass *factory_class = GTK_LIST_ITEM_FACTORY_CLASS (klass);
object_class->finalize = gtk_functions_list_item_factory_finalize;
factory_class->setup = gtk_functions_list_item_factory_setup;
factory_class->update = gtk_functions_list_item_factory_update;
}
static void
gtk_functions_list_item_factory_init (GtkFunctionsListItemFactory *self)
{
}
/**
* gtk_functions_list_item_factory_new: (skip)
* @setup_func: (scope call) (destroy user_destroy): the setup function for the list item factory
* @bind_func: (scope call) (destroy user_destroy): the bind function for the list item factory
* @user_data: user data for the @setup_func and @bind_func functions
* @user_destroy: a function called to destroy @user_data
*
* Creates a new #GtkListItemFactory with the given functions.
*
* Returns: (transfer full): the newly created list item factory object
*/
GtkListItemFactory *
gtk_functions_list_item_factory_new (GtkListItemSetupFunc setup_func,
GtkListItemBindFunc bind_func,
gpointer user_data,
GDestroyNotify user_destroy)
{
GtkFunctionsListItemFactory *self;
g_return_val_if_fail (setup_func || bind_func, NULL);
g_return_val_if_fail (user_data != NULL || user_destroy == NULL, NULL);
self = g_object_new (GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, NULL);
self->setup_func = setup_func;
self->bind_func = bind_func;
self->user_data = user_data;
self->user_destroy = user_destroy;
return GTK_LIST_ITEM_FACTORY (self);
}
+82
View File
@@ -0,0 +1,82 @@
/*
* Copyright © 2019 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_FUNCTIONS_LIST_ITEM_FACTORY_H__
#define __GTK_FUNCTIONS_LIST_ITEM_FACTORY_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gtk/gtklistitemfactory.h>
#include <gtk/gtklistitem.h>
G_BEGIN_DECLS
#define GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY (gtk_functions_list_item_factory_get_type ())
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactory))
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactoryClass))
#define GTK_IS_FUNCTIONS_LIST_ITEM_FACTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY))
#define GTK_IS_FUNCTIONS_LIST_ITEM_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY))
#define GTK_FUNCTIONS_LIST_ITEM_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_FUNCTIONS_LIST_ITEM_FACTORY, GtkFunctionsListItemFactoryClass))
typedef struct _GtkFunctionsListItemFactory GtkFunctionsListItemFactory;
typedef struct _GtkFunctionsListItemFactoryClass GtkFunctionsListItemFactoryClass;
/**
* GtkListItemSetupFunc:
* @item: the #GtkListItem to set up
* @user_data: (closure): user data
*
* Called whenever a new list item needs to be setup for managing a row in
* the list.
*
* At this point, the list item is not bound yet, so gtk_list_item_get_item()
* will return %NULL.
* The list item will later be bound to an item via the #GtkListItemBindFunc.
*/
typedef void (* GtkListItemSetupFunc) (GtkListItem *item, gpointer user_data);
/**
* GtkListItemBindFunc:
* @item: the #GtkListItem to bind
* @user_data: (closure): user data
*
* Binds a#GtkListItem previously set up via a #GtkListItemSetupFunc to
* an @item.
*
* Rebinding a @item to different @items is supported as well as
* unbinding it by setting @item to %NULL.
*/
typedef void (* GtkListItemBindFunc) (GtkListItem *item,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
GType gtk_functions_list_item_factory_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkListItemFactory * gtk_functions_list_item_factory_new (GtkListItemSetupFunc setup_func,
GtkListItemBindFunc bind_func,
gpointer user_data,
GDestroyNotify user_destroy);
G_END_DECLS
#endif /* __GTK_FUNCTIONS_LIST_ITEM_FACTORY_H__ */
-2
View File
@@ -1171,8 +1171,6 @@ gtk_grid_view_init (GtkGridView *self)
gtk_list_base_set_anchor_max_widgets (GTK_LIST_BASE (self),
self->max_columns * GTK_GRID_VIEW_MAX_VISIBLE_ROWS,
self->max_columns);
gtk_widget_add_css_class (GTK_WIDGET (self), "view");
}
/**
+1 -3
View File
@@ -595,7 +595,7 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
g_param_spec_boolean ("show-title-buttons",
P_("Show title buttons"),
P_("Whether to show title buttons"),
TRUE,
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
/**
@@ -629,7 +629,6 @@ gtk_header_bar_init (GtkHeaderBar *bar)
priv->title_widget = NULL;
priv->decoration_layout = NULL;
priv->show_title_buttons = TRUE;
priv->state = GDK_SURFACE_STATE_WITHDRAWN;
priv->handle = gtk_window_handle_new ();
@@ -647,7 +646,6 @@ gtk_header_bar_init (GtkHeaderBar *bar)
gtk_center_box_set_end_widget (GTK_CENTER_BOX (priv->center_box), priv->end_box);
construct_title_label (bar);
create_window_controls (bar);
}
static GtkBuildableIface *parent_buildable_iface;
+4 -7
View File
@@ -3573,15 +3573,12 @@ static void
gtk_label_unrealize (GtkWidget *widget)
{
GtkLabel *self = GTK_LABEL (widget);
GdkClipboard *clipboard;
clipboard = gtk_widget_get_primary_clipboard (widget);
if (self->select_info &&
self->select_info->provider)
{
GdkClipboard *clipboard = gtk_widget_get_primary_clipboard (widget);
if (gdk_clipboard_get_content (clipboard) == self->select_info->provider)
gdk_clipboard_set_content (clipboard, NULL);
}
gdk_clipboard_get_content (clipboard) == self->select_info->provider)
gdk_clipboard_set_content (clipboard, NULL);
GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget);
}
+3 -3
View File
@@ -40,7 +40,7 @@
* Because views do not display the whole list at once but only a few
* items, they only need to maintain a few widgets at a time. They will
* instruct the #GtkListItemFactory to create these widgets and bind them
* to the items that are currently displayed.
* to the items that are currently displayed.
* As the list model changes or the user scrolls to the list, the items will
* change and the view will instruct the factory to bind the widgets to those
* new items.
@@ -56,13 +56,13 @@
* Various implementations of #GtkListItemFactory exist to allow you different
* ways to provide those widgets. The most common implementations are
* #GtkBuilderListItemFactory which takes a #GtkBuilder .ui file and then creates
* widgets and manages everything automatically from the information in that file
* and manages widgets everything automatically from the information in that file
* and #GtkSignalListItemFactory which allows you to connect to signals with your
* own code and retain full control over how the widgets are setup and managed.
*
* A #GtkListItemFactory is supposed to be final - that means its behavior should
* not change and the first widget created from it should behave the same way as
* the last widget created from it.
* the last widget created from it.
* If you intend to do changes to the behavior, it is recommended that you create
* a new #GtkListItemFactory which will allow the views to recreate its widgets.
*
-2
View File
@@ -925,8 +925,6 @@ gtk_list_view_init (GtkListView *self)
gtk_list_base_set_anchor_max_widgets (GTK_LIST_BASE (self),
GTK_LIST_VIEW_MAX_LIST_ITEMS,
GTK_LIST_VIEW_EXTRA_ITEMS);
gtk_widget_add_css_class (GTK_WIDGET (self), "view");
}
/**
-16
View File
@@ -386,19 +386,3 @@ gtk_multi_selection_new (GListModel *model)
"model", model,
NULL);
}
/**
* gtk_multi_selection_get_model:
* @self: a #GtkMultiSelection
*
* Returns the underlying model of @self.
*
* Returns: (transfer none): the underlying model
*/
GListModel *
gtk_multi_selection_get_model (GtkMultiSelection *self)
{
g_return_val_if_fail (GTK_IS_MULTI_SELECTION (self), NULL);
return self->model;
}
-2
View File
@@ -33,8 +33,6 @@ G_DECLARE_FINAL_TYPE (GtkMultiSelection, gtk_multi_selection, GTK, MULTI_SELECTI
GDK_AVAILABLE_IN_ALL
GListModel * gtk_multi_selection_new (GListModel *model);
GDK_AVAILABLE_IN_ALL
GListModel * gtk_multi_selection_get_model (GtkMultiSelection *self);
G_END_DECLS
+11
View File
@@ -250,6 +250,16 @@ G_DEFINE_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET,
static guint signals[LAST_SIGNAL];
static GParamSpec *properties[LAST_PROP];
static void
gtk_range_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkRange *range = GTK_RANGE (widget);
GtkRangePrivate *priv = gtk_range_get_instance_private (range);
gtk_widget_snapshot_child (widget, priv->trough_widget, snapshot);
}
static void
gtk_range_class_init (GtkRangeClass *class)
{
@@ -265,6 +275,7 @@ gtk_range_class_init (GtkRangeClass *class)
gobject_class->dispose = gtk_range_dispose;
widget_class->measure = gtk_range_measure;
widget_class->snapshot = gtk_range_snapshot;
widget_class->size_allocate = gtk_range_size_allocate;
widget_class->unmap = gtk_range_unmap;
widget_class->direction_changed = gtk_range_direction_changed;
+12 -14
View File
@@ -47,12 +47,14 @@ static void
gtk_theming_background_snapshot_color (GtkCssBoxes *boxes,
GtkSnapshot *snapshot,
const GdkRGBA *bg_color,
guint n_bg_values)
const GtkCssValue *background_image)
{
const GskRoundedRect *box;
gint n_values;
GtkCssArea clip;
clip = _gtk_css_area_value_get (_gtk_css_array_value_get_nth (boxes->style->background->background_clip, n_bg_values - 1));
n_values = _gtk_css_array_value_get_n_values (background_image);
clip = _gtk_css_area_value_get (_gtk_css_array_value_get_nth (boxes->style->background->background_clip, n_values - 1));
box = gtk_css_boxes_get_box (boxes, clip);
if (gsk_rounded_rect_is_rectilinear (box))
@@ -92,6 +94,9 @@ gtk_theming_background_snapshot_layer (GtkCssBoxes *bg,
pos = _gtk_css_array_value_get_nth (background->background_position, idx);
repeat = _gtk_css_array_value_get_nth (background->background_repeat, idx);
hrepeat = _gtk_css_background_repeat_value_get_x (repeat);
vrepeat = _gtk_css_background_repeat_value_get_y (repeat);
origin = gtk_css_boxes_get_box (bg,
_gtk_css_area_value_get (
@@ -120,13 +125,8 @@ gtk_theming_background_snapshot_layer (GtkCssBoxes *bg,
/* optimization */
if (image_width == width)
hrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT;
else
hrepeat = _gtk_css_background_repeat_value_get_x (repeat);
if (image_height == height)
vrepeat = GTK_CSS_REPEAT_STYLE_NO_REPEAT;
else
vrepeat = _gtk_css_background_repeat_value_get_y (repeat);
gtk_snapshot_push_debug (snapshot, "Layer %u", idx);
gtk_snapshot_push_rounded_clip (snapshot, clip);
@@ -262,8 +262,7 @@ gtk_css_style_snapshot_background (GtkCssBoxes *boxes,
gboolean has_bg_color;
gboolean has_bg_image;
gboolean has_shadow;
int idx;
guint number_of_layers;
gint idx;
if (background->base.type == GTK_CSS_BACKGROUND_INITIAL_VALUES)
return;
@@ -287,11 +286,10 @@ gtk_css_style_snapshot_background (GtkCssBoxes *boxes,
snapshot,
gtk_css_boxes_get_border_box (boxes));
number_of_layers = _gtk_css_array_value_get_n_values (background_image);
if (has_bg_image)
{
GtkCssValue *blend_modes = background->background_blend_mode;
const int number_of_layers = _gtk_css_array_value_get_n_values (background_image);
GskBlendMode *blend_mode_values = g_alloca (sizeof (GskBlendMode) * number_of_layers);
for (idx = number_of_layers - 1; idx >= 0; idx--)
@@ -303,7 +301,7 @@ gtk_css_style_snapshot_background (GtkCssBoxes *boxes,
}
if (has_bg_color)
gtk_theming_background_snapshot_color (boxes, snapshot, bg_color, number_of_layers);
gtk_theming_background_snapshot_color (boxes, snapshot, bg_color, background_image);
for (idx = number_of_layers - 1; idx >= 0; idx--)
{
@@ -321,7 +319,7 @@ gtk_css_style_snapshot_background (GtkCssBoxes *boxes,
}
else if (has_bg_color)
{
gtk_theming_background_snapshot_color (boxes, snapshot, bg_color, number_of_layers);
gtk_theming_background_snapshot_color (boxes, snapshot, bg_color, background_image);
}
if (has_shadow)
+44 -14
View File
@@ -79,23 +79,22 @@
*
* |[<!-- language="plain" -->
* scale[.fine-tune][.marks-before][.marks-after]
* [value][.top][.right][.bottom][.left]
* marks.top
* mark
* [label]
* indicator
*
* mark
* marks.bottom
* mark
* indicator
* [label]
*
* mark
* trough
* [fill]
* [highlight]
* slider
* [value][.top][.right][.bottom][.left]
* trough
* [fill]
* [highlight]
* slider
* marks.bottom
* mark
* indicator
* [label]
* mark
* ]|
*
* GtkScale has a main CSS node with name scale and a subnode for its contents,
@@ -198,6 +197,8 @@ static void gtk_scale_measure (GtkWidget *widget,
static void gtk_scale_get_range_border (GtkRange *range,
GtkBorder *border);
static void gtk_scale_finalize (GObject *object);
static void gtk_scale_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot);
static void gtk_scale_real_get_layout_offsets (GtkScale *scale,
gint *x,
gint *y);
@@ -660,6 +661,7 @@ gtk_scale_class_init (GtkScaleClass *class)
gobject_class->notify = gtk_scale_notify;
gobject_class->finalize = gtk_scale_finalize;
widget_class->snapshot = gtk_scale_snapshot;
widget_class->size_allocate = gtk_scale_size_allocate;
widget_class->measure = gtk_scale_measure;
widget_class->grab_focus = gtk_widget_grab_focus_self;
@@ -1091,9 +1093,14 @@ gtk_scale_set_draw_value (GtkScale *scale,
"css-name", "value",
"label", txt,
NULL);
g_free (txt);
gtk_widget_insert_after (priv->value_widget, GTK_WIDGET (scale), NULL);
if (priv->value_pos == GTK_POS_TOP || priv->value_pos == GTK_POS_LEFT)
gtk_widget_insert_after (priv->value_widget, GTK_WIDGET (scale), NULL);
else
gtk_widget_insert_before (priv->value_widget, GTK_WIDGET (scale), NULL);
gtk_range_set_round_digits (GTK_RANGE (scale), priv->digits);
update_value_position (scale);
update_label_request (scale);
@@ -1462,6 +1469,25 @@ gtk_scale_measure (GtkWidget *widget,
}
}
static void
gtk_scale_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkScale *scale = GTK_SCALE (widget);
GtkScalePrivate *priv = gtk_scale_get_instance_private (scale);
if (priv->top_marks_widget)
gtk_widget_snapshot_child (widget, priv->top_marks_widget, snapshot);
if (priv->bottom_marks_widget)
gtk_widget_snapshot_child (widget, priv->bottom_marks_widget, snapshot);
if (priv->value_widget)
gtk_widget_snapshot_child (widget, priv->value_widget, snapshot);
GTK_WIDGET_CLASS (gtk_scale_parent_class)->snapshot (widget, snapshot);
}
static void
gtk_scale_real_get_layout_offsets (GtkScale *scale,
gint *x,
@@ -1696,7 +1722,9 @@ gtk_scale_add_mark (GtkScale *scale,
gtk_widget_insert_after (priv->top_marks_widget,
GTK_WIDGET (scale),
priv->value_widget);
(priv->value_widget &&
(priv->value_pos == GTK_POS_TOP || priv->value_pos == GTK_POS_LEFT)) ?
priv->value_widget : NULL);
gtk_widget_add_css_class (priv->top_marks_widget, GTK_STYLE_CLASS_TOP);
}
marks_widget = priv->top_marks_widget;
@@ -1714,7 +1742,9 @@ gtk_scale_add_mark (GtkScale *scale,
gtk_widget_insert_before (priv->bottom_marks_widget,
GTK_WIDGET (scale),
gtk_range_get_trough_widget (GTK_RANGE (scale)));
(priv->value_widget &&
(priv->value_pos == GTK_POS_BOTTOM || priv->value_pos == GTK_POS_RIGHT)) ?
priv->value_widget: NULL);
gtk_widget_add_css_class (priv->bottom_marks_widget, GTK_STYLE_CLASS_BOTTOM);
}
marks_widget = priv->bottom_marks_widget;
+2 -13
View File
@@ -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
-373
View File
@@ -1,373 +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
*/
#include "config.h"
#include "gtkselectionfiltermodel.h"
#include "gtkbitset.h"
#include "gtkintl.h"
#include "gtkprivate.h"
/**
* SECTION:gtkselectionfiltermodel
* @title: GtkSelectionFilterModel
* @short_description: A list model that turns a selection in a model
* @see_also: #GtkSelectionModel
*
* #GtkSelectionFilterModel is a list model that presents the
* selected items in a #GtkSelectionModel as its own list model.
*/
enum {
PROP_0,
PROP_ITEM_TYPE,
PROP_MODEL,
NUM_PROPERTIES
};
struct _GtkSelectionFilterModel
{
GObject parent_instance;
GType item_type;
GtkSelectionModel *model;
GtkBitset *selection;
};
struct _GtkSelectionFilterModelClass
{
GObjectClass parent_class;
};
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
static GType
gtk_selection_filter_model_get_item_type (GListModel *list)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
return self->item_type;
}
static guint
gtk_selection_filter_model_get_n_items (GListModel *list)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
if (self->selection)
return gtk_bitset_get_size (self->selection);
return 0;
}
static gpointer
gtk_selection_filter_model_get_item (GListModel *list,
guint position)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
position = gtk_bitset_get_nth (self->selection, position);
return g_list_model_get_item (G_LIST_MODEL (self->model), position);
}
static void
gtk_selection_filter_model_list_model_init (GListModelInterface *iface)
{
iface->get_item_type = gtk_selection_filter_model_get_item_type;
iface->get_n_items = gtk_selection_filter_model_get_n_items;
iface->get_item = gtk_selection_filter_model_get_item;
}
G_DEFINE_TYPE_WITH_CODE (GtkSelectionFilterModel, gtk_selection_filter_model, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_selection_filter_model_list_model_init))
static void
selection_filter_model_items_changed (GtkSelectionFilterModel *self,
guint position,
guint removed,
guint added)
{
GtkBitset *selection;
guint sel_position = 0;
guint sel_removed = 0;
guint sel_added = 0;
selection = gtk_selection_model_get_selection (self->model);
if (position > 0)
sel_position = gtk_bitset_get_size_in_range (self->selection, 0, position - 1);
if (removed > 0)
sel_removed = gtk_bitset_get_size_in_range (self->selection, position, position + removed - 1);
if (added > 0)
sel_added = gtk_bitset_get_size_in_range (selection, position, position + added - 1);
gtk_bitset_unref (self->selection);
self->selection = gtk_bitset_copy (selection);
gtk_bitset_unref (selection);
if (sel_removed > 0 || sel_added > 0)
g_list_model_items_changed (G_LIST_MODEL (self), sel_position, sel_removed, sel_added);
}
static void
gtk_selection_filter_model_items_changed_cb (GListModel *model,
guint position,
guint removed,
guint added,
GtkSelectionFilterModel *self)
{
selection_filter_model_items_changed (self, position, removed, added);
}
static void
gtk_selection_filter_model_selection_changed_cb (GListModel *model,
guint position,
guint n_items,
GtkSelectionFilterModel *self)
{
selection_filter_model_items_changed (self, position, n_items, n_items);
}
static void
gtk_selection_filter_model_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
switch (prop_id)
{
case PROP_ITEM_TYPE:
self->item_type = g_value_get_gtype (value);
break;
case PROP_MODEL:
gtk_selection_filter_model_set_model (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_selection_filter_model_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
switch (prop_id)
{
case PROP_ITEM_TYPE:
g_value_set_gtype (value, self->item_type);
break;
case PROP_MODEL:
g_value_set_object (value, self->model);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_selection_filter_model_clear_model (GtkSelectionFilterModel *self)
{
if (self->model == NULL)
return;
g_signal_handlers_disconnect_by_func (self->model, gtk_selection_filter_model_items_changed_cb, self);
g_signal_handlers_disconnect_by_func (self->model, gtk_selection_filter_model_selection_changed_cb, self);
g_clear_object (&self->model);
g_clear_pointer (&self->selection, gtk_bitset_unref);
}
static void
gtk_selection_filter_model_dispose (GObject *object)
{
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
gtk_selection_filter_model_clear_model (self);
G_OBJECT_CLASS (gtk_selection_filter_model_parent_class)->dispose (object);
}
static void
gtk_selection_filter_model_class_init (GtkSelectionFilterModelClass *class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
gobject_class->set_property = gtk_selection_filter_model_set_property;
gobject_class->get_property = gtk_selection_filter_model_get_property;
gobject_class->dispose = gtk_selection_filter_model_dispose;
/**
* GtkSelectionFilterModel:item-type:
*
* The #GType for elements of this object
*/
properties[PROP_ITEM_TYPE] =
g_param_spec_gtype ("item-type",
P_("Item type"),
P_("The type of elements of this object"),
G_TYPE_OBJECT,
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkSelectionFilterModel:model:
*
* The model being filtered
*/
properties[PROP_MODEL] =
g_param_spec_object ("model",
P_("Model"),
P_("The model being filtered"),
GTK_TYPE_SELECTION_MODEL,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
}
static void
gtk_selection_filter_model_init (GtkSelectionFilterModel *self)
{
}
/**
* gtk_selection_filter_model_new:
* @model: the selection model to filter
*
* Creates a new #GtkSelectionFilterModel that will include the
* selected items from the underlying selection model.
*
* Returns: a new #GtkSelectionFilterModel
**/
GtkSelectionFilterModel *
gtk_selection_filter_model_new (GtkSelectionModel *model)
{
GtkSelectionFilterModel *result;
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), NULL);
result = g_object_new (GTK_TYPE_SELECTION_FILTER_MODEL,
"item-type", g_list_model_get_item_type (G_LIST_MODEL (model)),
"model", model,
NULL);
return result;
}
/**
* gtk_selection_filter_model_new_for_type:
* @item_type: the type of the items that will be returned
*
* Creates a new empty selection filter model set up to return items
* of type @item_type. It is up to the application to set a proper
* selection model to ensure the item type is matched.
*
* Returns: a new #GtkSelectionFilterModel
**/
GtkSelectionFilterModel *
gtk_selection_filter_model_new_for_type (GType item_type)
{
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
return g_object_new (GTK_TYPE_SELECTION_FILTER_MODEL,
"item-type", item_type,
NULL);
}
/**
* gtk_selection_filter_model_set_model:
* @self: a #GtkSelectionFilterModel
* @model: (allow-none): The model to be filtered
*
* Sets the model to be filtered.
*
* Note that GTK makes no effort to ensure that @model conforms to
* the item type of @self. It assumes that the caller knows what they
* are doing and have set up an appropriate filter to ensure that item
* types match.
**/
void
gtk_selection_filter_model_set_model (GtkSelectionFilterModel *self,
GtkSelectionModel *model)
{
guint removed, added;
g_return_if_fail (GTK_IS_SELECTION_FILTER_MODEL (self));
g_return_if_fail (model == NULL || GTK_IS_SELECTION_MODEL (model));
g_return_if_fail (model == NULL || g_type_is_a (g_list_model_get_item_type (G_LIST_MODEL (model)),
self->item_type));
if (self->model == model)
return;
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
gtk_selection_filter_model_clear_model (self);
if (model)
{
GtkBitset *selection;
self->model = g_object_ref (model);
selection = gtk_selection_model_get_selection (self->model);
self->selection = gtk_bitset_copy (selection);
gtk_bitset_unref (selection);
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_selection_filter_model_items_changed_cb), self);
g_signal_connect (model, "selection-changed", G_CALLBACK (gtk_selection_filter_model_selection_changed_cb), self);
}
added = g_list_model_get_n_items (G_LIST_MODEL (self));
if (removed > 0 || added > 0)
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
}
/**
* gtk_selection_filter_model_get_model:
* @self: a #GtkSelectionFilterModel
*
* Gets the model currently filtered or %NULL if none.
*
* Returns: (nullable) (transfer none): The model that gets filtered
**/
GtkSelectionModel *
gtk_selection_filter_model_get_model (GtkSelectionFilterModel *self)
{
g_return_val_if_fail (GTK_IS_SELECTION_FILTER_MODEL (self), NULL);
return self->model;
}
-52
View File
@@ -1,52 +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
*/
#ifndef __GTK_SELECTION_FILTER_MODEL_H__
#define __GTK_SELECTION_FILTER_MODEL_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gio/gio.h>
#include <gtk/gtkselectionmodel.h>
G_BEGIN_DECLS
#define GTK_TYPE_SELECTION_FILTER_MODEL (gtk_selection_filter_model_get_type ())
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GtkSelectionFilterModel, gtk_selection_filter_model, GTK, SELECTION_FILTER_MODEL, GObject)
GDK_AVAILABLE_IN_ALL
GtkSelectionFilterModel * gtk_selection_filter_model_new (GtkSelectionModel *model);
GDK_AVAILABLE_IN_ALL
GtkSelectionFilterModel * gtk_selection_filter_model_new_for_type (GType item_type);
GDK_AVAILABLE_IN_ALL
void gtk_selection_filter_model_set_model (GtkSelectionFilterModel *self,
GtkSelectionModel *model);
GDK_AVAILABLE_IN_ALL
GtkSelectionModel * gtk_selection_filter_model_get_model (GtkSelectionFilterModel *self);
G_END_DECLS
#endif /* __GTK_SELECTION_FILTER_MODEL_H__ */
+3 -1
View File
@@ -860,7 +860,9 @@ gtk_shortcuts_window_init (GtkShortcutsWindow *self)
priv->search_text_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->search_image_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
priv->header_bar = GTK_HEADER_BAR (gtk_header_bar_new ());
priv->header_bar = g_object_new (GTK_TYPE_HEADER_BAR,
"show-title-buttons", TRUE,
NULL);
gtk_window_set_titlebar (GTK_WINDOW (self), GTK_WIDGET (priv->header_bar));
search_button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
+2 -2
View File
@@ -110,9 +110,9 @@ gtk_string_filter_match (GtkFilter *filter,
!gtk_expression_evaluate (self->expression, item, &value))
return FALSE;
s = g_value_get_string (&value);
if (s == NULL)
return FALSE;
prepared = gtk_string_filter_prepare (self, s);
if (prepared == NULL)
return FALSE;
switch (self->match_mode)
{
+135 -84
View File
@@ -25,6 +25,7 @@
#include "gtkbuilderprivate.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkbitset.h"
/**
* SECTION:gtkstringlist
@@ -138,31 +139,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)
{
GtkStringObject *obj;
obj = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
obj->string = string;
return obj;
}
/**
* gtk_string_object_get_string:
* @self: a #GtkStringObject
@@ -183,7 +166,8 @@ struct _GtkStringList
{
GObject parent_instance;
GSequence *items;
GPtrArray *items;
GtkBitset *objects;
};
struct _GtkStringListClass
@@ -202,7 +186,56 @@ gtk_string_list_get_n_items (GListModel *list)
{
GtkStringList *self = GTK_STRING_LIST (list);
return g_sequence_get_length (self->items);
return self->items->len;
}
static inline gboolean
IS_STRING (gpointer item)
{
return GPOINTER_TO_INT (item) & 0x1;
}
static inline gpointer
TO_STRING (gpointer item)
{
return GINT_TO_POINTER (GPOINTER_TO_INT (item) & ~0x1);
}
static inline gpointer
MAKE_STRING (const char *str)
{
return GINT_TO_POINTER (GPOINTER_TO_INT (str) | 0x1);
}
static GtkStringObject *
find_unused_object (GtkStringList *self)
{
GtkBitsetIter iter;
guint position;
gpointer item;
if (gtk_bitset_iter_init_first (&iter, self->objects, &position))
{
do
{
item = g_ptr_array_index (self->items, position);
g_assert (!IS_STRING (item));
if (G_OBJECT (item)->ref_count == 1)
{
GtkStringObject *obj;
obj = GTK_STRING_OBJECT (item);
g_ptr_array_index (self->items, position) = MAKE_STRING (obj->string);
obj->string = NULL;
gtk_bitset_remove (self->objects, position);
return obj;
}
} while (gtk_bitset_iter_next (&iter, &position));
}
return NULL;
}
static gpointer
@@ -210,14 +243,30 @@ gtk_string_list_get_item (GListModel *list,
guint position)
{
GtkStringList *self = GTK_STRING_LIST (list);
GSequenceIter *iter;
gpointer item;
iter = g_sequence_get_iter_at_pos (self->items, position);
if (g_sequence_iter_is_end (iter))
if (position >= self->items->len)
return NULL;
else
return g_object_ref (g_sequence_get (iter));
item = g_ptr_array_index (self->items, position);
if (IS_STRING (item))
{
GtkStringObject *obj;
obj = find_unused_object (self);
if (!obj)
obj = g_object_new (GTK_TYPE_STRING_OBJECT, NULL);
obj->string = TO_STRING (item);
g_ptr_array_index (self->items, position) = obj;
gtk_bitset_add (self->objects, position);
item = obj;
}
g_print ("live string objects: %lu\n", gtk_bitset_get_size (self->objects));
return g_object_ref (item);
}
static void
@@ -324,7 +373,7 @@ item_end_element (GtkBuildableParseContext *context,
g_string_assign (data->string, translated);
}
g_sequence_append (data->list->items, gtk_string_object_new (data->string->str));
g_ptr_array_add (data->list->items, MAKE_STRING (g_strdup (data->string->str)));
}
data->translatable = FALSE;
@@ -404,7 +453,8 @@ gtk_string_list_dispose (GObject *object)
{
GtkStringList *self = GTK_STRING_LIST (object);
g_clear_pointer (&self->items, g_sequence_free);
g_clear_pointer (&self->items, g_ptr_array_unref);
g_clear_pointer (&self->objects, gtk_bitset_unref);
G_OBJECT_CLASS (gtk_string_list_parent_class)->dispose (object);
}
@@ -417,10 +467,20 @@ gtk_string_list_class_init (GtkStringListClass *class)
gobject_class->dispose = gtk_string_list_dispose;
}
static void
free_string_or_object (gpointer data)
{
if (IS_STRING (data))
g_free (TO_STRING (data));
else
g_object_unref (data);
}
static void
gtk_string_list_init (GtkStringList *self)
{
self->items = g_sequence_new (g_object_unref);
self->items = g_ptr_array_new_full (32, free_string_or_object);
self->objects = gtk_bitset_new_empty ();
}
/**
@@ -432,15 +492,13 @@ gtk_string_list_init (GtkStringList *self)
* Returns: a new #GtkStringList
*/
GtkStringList *
gtk_string_list_new (const char **strings)
gtk_string_list_new (const char * const *strings)
{
GtkStringList *self;
guint i;
self = g_object_new (GTK_TYPE_STRING_LIST, NULL);
for (i = 0; strings[i]; i++)
g_sequence_append (self->items, gtk_string_object_new (strings[i]));
gtk_string_list_splice (self, 0, 0, strings);
return self;
}
@@ -450,11 +508,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,44 +524,41 @@ 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 i;
guint n_additions;
gpointer item;
g_return_if_fail (GTK_IS_STRING_LIST (self));
g_return_if_fail (position + n_removals >= position); /* overflow */
n_items = g_sequence_get_length (self->items);
n_items = self->items->len;
g_return_if_fail (position + n_removals <= n_items);
it = g_sequence_get_iter_at_pos (self->items, position);
for (i = 0; i < n_removals; i++)
g_ptr_array_remove_index (self->items, position);
if (n_removals)
if (additions)
{
GSequenceIter *end;
end = g_sequence_iter_move (it, n_removals);
g_sequence_remove_range (it, end);
it = end;
}
if (n_additions)
{
gint i;
for (i = 0; i < n_additions; i++)
for (i = 0; additions[i]; i++)
{
g_sequence_insert_before (it, gtk_string_object_new (additions[i]));
item = MAKE_STRING (g_strdup (additions[i]));
g_ptr_array_insert (self->items, position + i, item);
}
n_additions = i;
}
else
n_additions = 0;
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
gtk_bitset_slice (self->objects, position, n_removals, n_additions);
if (n_removals || n_additions)
g_list_model_items_changed (G_LIST_MODEL (self), position, n_removals, n_additions);
}
/**
@@ -522,11 +576,13 @@ gtk_string_list_append (GtkStringList *self,
const char *string)
{
guint n_items;
gpointer item;
g_return_if_fail (GTK_IS_STRING_LIST (self));
n_items = g_sequence_get_length (self->items);
g_sequence_append (self->items, gtk_string_object_new (string));
n_items = self->items->len;
item = MAKE_STRING (g_strdup (string));
g_ptr_array_add (self->items, item);
g_list_model_items_changed (G_LIST_MODEL (self), n_items, 0, 1);
}
@@ -551,11 +607,13 @@ gtk_string_list_take (GtkStringList *self,
char *string)
{
guint n_items;
gpointer item;
g_return_if_fail (GTK_IS_STRING_LIST (self));
n_items = g_sequence_get_length (self->items);
g_sequence_append (self->items, gtk_string_object_new_take (string));
n_items = self->items->len;
item = MAKE_STRING (string);
g_ptr_array_add (self->items, item);
g_list_model_items_changed (G_LIST_MODEL (self), n_items, 0, 1);
}
@@ -572,14 +630,13 @@ void
gtk_string_list_remove (GtkStringList *self,
guint position)
{
GSequenceIter *iter;
g_return_if_fail (GTK_IS_STRING_LIST (self));
iter = g_sequence_get_iter_at_pos (self->items, position);
g_return_if_fail (!g_sequence_iter_is_end (iter));
if (position >= self->items->len)
return;
g_sequence_remove (iter);
g_ptr_array_remove_index (self->items, position);
gtk_bitset_slice (self->objects, position, 1, 0);
g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
}
@@ -589,8 +646,8 @@ gtk_string_list_remove (GtkStringList *self,
* @self: a #GtkStringList
* @position: the position to get the string for
*
* Gets the string that is at @position in @self. @position
* must be smaller than the current length of the list.
* Gets the string that is at @position in @self. If @self
* does not contain @position items, %NULL is returned.
*
* This function returns the const char *. To get the
* object wrapping it, use g_list_model_get_item().
@@ -601,20 +658,14 @@ const char *
gtk_string_list_get_string (GtkStringList *self,
guint position)
{
GSequenceIter *iter;
gpointer item;
g_return_val_if_fail (GTK_IS_STRING_LIST (self), NULL);
iter = g_sequence_get_iter_at_pos (self->items, position);
item = g_ptr_array_index (self->items, position);
if (g_sequence_iter_is_end (iter))
{
return NULL;
}
if (IS_STRING (item))
return (const char *)TO_STRING (item);
else
{
GtkStringObject *obj = g_sequence_get (iter);
return obj->string;
}
return GTK_STRING_OBJECT (item)->string;
}
+13 -14
View File
@@ -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
+72 -20
View File
@@ -111,13 +111,27 @@ struct _GtkTextLayoutPrivate
GtkTextLineDisplayCache *cache;
};
static GtkTextLineData *gtk_text_layout_real_wrap (GtkTextLayout *layout,
GtkTextLine *line,
/* may be NULL */
GtkTextLineData *line_data);
static void gtk_text_layout_invalidated (GtkTextLayout *layout);
static void gtk_text_layout_real_invalidate (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end);
static void gtk_text_layout_real_invalidate_cursors(GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end);
static void gtk_text_layout_invalidate_cache (GtkTextLayout *layout,
GtkTextLine *line,
gboolean cursors_only);
static void gtk_text_layout_invalidate_cursor_line (GtkTextLayout *layout,
gboolean cursors_only);
static void gtk_text_layout_real_free_line_data (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data);
static void gtk_text_layout_emit_changed (GtkTextLayout *layout,
gint y,
gint old_height,
@@ -235,11 +249,16 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
object_class->dispose = gtk_text_layout_dispose;
object_class->finalize = gtk_text_layout_finalize;
klass->wrap = gtk_text_layout_real_wrap;
klass->invalidate = gtk_text_layout_real_invalidate;
klass->invalidate_cursors = gtk_text_layout_real_invalidate_cursors;
klass->free_line_data = gtk_text_layout_real_free_line_data;
signals[INVALIDATED] =
g_signal_new (I_("invalidated"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
G_STRUCT_OFFSET (GtkTextLayoutClass, invalidated),
NULL, NULL,
NULL,
G_TYPE_NONE,
@@ -249,7 +268,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
g_signal_new (I_("changed"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
G_STRUCT_OFFSET (GtkTextLayoutClass, changed),
NULL, NULL,
_gtk_marshal_VOID__INT_INT_INT,
G_TYPE_NONE,
@@ -264,7 +283,7 @@ gtk_text_layout_class_init (GtkTextLayoutClass *klass)
g_signal_new (I_("allocate-child"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
0,
G_STRUCT_OFFSET (GtkTextLayoutClass, allocate_child),
NULL, NULL,
_gtk_marshal_VOID__OBJECT_INT_INT,
G_TYPE_NONE,
@@ -671,6 +690,39 @@ gtk_text_layout_cursors_changed (GtkTextLayout *layout,
gtk_text_layout_emit_changed (layout, y, old_height, new_height);
}
void
gtk_text_layout_free_line_data (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data)
{
GTK_TEXT_LAYOUT_GET_CLASS (layout)->free_line_data (layout, line, line_data);
}
void
gtk_text_layout_invalidate (GtkTextLayout *layout,
const GtkTextIter *start_index,
const GtkTextIter *end_index)
{
GTK_TEXT_LAYOUT_GET_CLASS (layout)->invalidate (layout, start_index, end_index);
}
void
gtk_text_layout_invalidate_cursors (GtkTextLayout *layout,
const GtkTextIter *start_index,
const GtkTextIter *end_index)
{
GTK_TEXT_LAYOUT_GET_CLASS (layout)->invalidate_cursors (layout, start_index, end_index);
}
GtkTextLineData*
gtk_text_layout_wrap (GtkTextLayout *layout,
GtkTextLine *line,
/* may be NULL */
GtkTextLineData *line_data)
{
return GTK_TEXT_LAYOUT_GET_CLASS (layout)->wrap (layout, line, line_data);
}
/*
* gtk_text_layout_get_lines:
@@ -840,10 +892,10 @@ gtk_text_layout_update_cursor_line (GtkTextLayout *layout)
gtk_text_line_display_cache_set_cursor_line (priv->cache, priv->cursor_line);
}
void
gtk_text_layout_invalidate (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end)
static void
gtk_text_layout_real_invalidate (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end)
{
GtkTextLine *line;
GtkTextLine *last_line;
@@ -884,20 +936,20 @@ gtk_text_layout_invalidate (GtkTextLayout *layout,
gtk_text_layout_invalidated (layout);
}
void
gtk_text_layout_invalidate_cursors (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end)
static void
gtk_text_layout_real_invalidate_cursors (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end)
{
GtkTextLayoutPrivate *priv = GTK_TEXT_LAYOUT_GET_PRIVATE (layout);
gtk_text_line_display_cache_invalidate_range (priv->cache, layout, start, end, TRUE);
gtk_text_layout_invalidated (layout);
}
void
gtk_text_layout_free_line_data (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data)
static void
gtk_text_layout_real_free_line_data (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data)
{
gtk_text_layout_invalidate_cache (layout, line, FALSE);
@@ -1096,11 +1148,11 @@ gtk_text_layout_validate (GtkTextLayout *layout,
}
}
GtkTextLineData *
gtk_text_layout_wrap (GtkTextLayout *layout,
GtkTextLine *line,
/* may be NULL */
GtkTextLineData *line_data)
static GtkTextLineData*
gtk_text_layout_real_wrap (GtkTextLayout *layout,
GtkTextLine *line,
/* may be NULL */
GtkTextLineData *line_data)
{
GtkTextLineDisplay *display;
PangoRectangle ink_rect, logical_rect;
+38
View File
@@ -167,6 +167,44 @@ struct _GtkTextLayout
struct _GtkTextLayoutClass
{
GObjectClass parent_class;
/* Some portion of the layout was invalidated
*/
void (*invalidated) (GtkTextLayout *layout);
/* A range of the layout changed appearance and possibly height
*/
void (*changed) (GtkTextLayout *layout,
gint y,
gint old_height,
gint new_height);
GtkTextLineData* (*wrap) (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data); /* may be NULL */
void (*get_log_attrs) (GtkTextLayout *layout,
GtkTextLine *line,
PangoLogAttr **attrs,
gint *n_attrs);
void (*invalidate) (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end);
void (*free_line_data) (GtkTextLayout *layout,
GtkTextLine *line,
GtkTextLineData *line_data);
void (*allocate_child) (GtkTextLayout *layout,
GtkWidget *child,
gint x,
gint y);
void (*invalidate_cursors) (GtkTextLayout *layout,
const GtkTextIter *start,
const GtkTextIter *end);
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
};
struct _GtkTextAttrAppearance
+1
View File
@@ -143,6 +143,7 @@
#define SCREEN_HEIGHT(widget) text_window_get_height (GTK_TEXT_VIEW (widget)->priv->text_window)
#define SPACE_FOR_CURSOR 1
#define CURSOR_ASPECT_RATIO (0.04)
typedef struct _GtkTextWindow GtkTextWindow;
typedef struct _GtkTextPendingScroll GtkTextPendingScroll;
+2 -2
View File
@@ -7377,14 +7377,14 @@ static void
gtk_widget_real_realize (GtkWidget *widget)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GdkFrameClock *frame_clock;
priv->realized = TRUE;
/* Connect frame clock */
frame_clock = gtk_widget_get_frame_clock (widget);
if (priv->tick_callbacks != NULL && !priv->clock_tick_id)
{
GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
priv->clock_tick_id = g_signal_connect (frame_clock, "update",
G_CALLBACK (gtk_widget_on_frame_clock_update),
widget);
+1
View File
@@ -4308,6 +4308,7 @@ gtk_window_realize (GtkWidget *widget)
if (priv->title_box == NULL)
{
priv->titlebar = gtk_header_bar_new ();
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (priv->titlebar), TRUE);
gtk_widget_add_css_class (priv->titlebar, GTK_STYLE_CLASS_TITLEBAR);
gtk_widget_add_css_class (priv->titlebar, "default-decoration");
+3 -3
View File
@@ -134,7 +134,7 @@ setup_parameter_cb (GtkSignalListItemFactory *factory,
label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.5);
gtk_list_item_set_child (list_item, label);
gtk_widget_add_css_class (label, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
}
static void
@@ -168,7 +168,7 @@ setup_state_cb (GtkSignalListItemFactory *factory,
gtk_widget_set_margin_end (label, 5);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_list_item_set_child (list_item, label);
gtk_widget_add_css_class (label, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
}
static void
@@ -215,7 +215,7 @@ bind_changes_cb (GtkSignalListItemFactory *factory,
name = action_holder_get_name (ACTION_HOLDER (item));
editor = gtk_inspector_action_editor_new (group, name, NULL);
gtk_widget_add_css_class (editor, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (editor), "cell");
gtk_list_item_set_child (list_item, editor);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2020 Red Hat, Inc.
* Copyright (c) 2014 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
@@ -18,7 +18,7 @@
#include "config.h"
#include <glib/gi18n-lib.h>
#include "tree-data.h"
#include "data-list.h"
#include "object-tree.h"
@@ -27,14 +27,10 @@
#include "gtktogglebutton.h"
#include "gtklabel.h"
#include "gtkstack.h"
#include "gtkboxlayout.h"
#include "gtkorientable.h"
struct _GtkInspectorTreeData
struct _GtkInspectorDataListPrivate
{
GtkWidget parent_instance;
GtkTreeModel *object;
GtkTreeModel *types;
GtkTreeView *view;
@@ -42,22 +38,13 @@ struct _GtkInspectorTreeData
gboolean show_data;
};
typedef struct _GtkInspectorTreeDataClass GtkInspectorTreeDataClass;
struct _GtkInspectorTreeDataClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GtkInspectorTreeData, gtk_inspector_tree_data, GTK_TYPE_WIDGET)
G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorDataList, gtk_inspector_data_list, GTK_TYPE_BOX)
static void
gtk_inspector_tree_data_init (GtkInspectorTreeData *sl)
gtk_inspector_data_list_init (GtkInspectorDataList *sl)
{
sl->priv = gtk_inspector_data_list_get_instance_private (sl);
gtk_widget_init_template (GTK_WIDGET (sl));
gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_widget_get_layout_manager (GTK_WIDGET (sl))),
GTK_ORIENTATION_VERTICAL);
}
static void
@@ -80,7 +67,7 @@ cell_data_func (GtkTreeViewColumn *col,
}
static void
add_columns (GtkInspectorTreeData *sl)
add_columns (GtkInspectorDataList *sl)
{
gint n_columns;
GtkCellRenderer *cell;
@@ -89,45 +76,45 @@ add_columns (GtkInspectorTreeData *sl)
GtkTreeViewColumn *col;
gint i;
n_columns = gtk_tree_model_get_n_columns (sl->object);
n_columns = gtk_tree_model_get_n_columns (sl->priv->object);
for (i = 0; i < n_columns; i++)
{
cell = gtk_cell_renderer_text_new ();
type = gtk_tree_model_get_column_type (sl->object, i);
type = gtk_tree_model_get_column_type (sl->priv->object, i);
title = g_strdup_printf ("%d: %s", i, g_type_name (type));
col = gtk_tree_view_column_new_with_attributes (title, cell, NULL);
g_object_set_data (G_OBJECT (col), "num", GINT_TO_POINTER (i));
gtk_tree_view_column_set_cell_data_func (col, cell, cell_data_func, sl, NULL);
gtk_tree_view_append_column (sl->view, col);
gtk_tree_view_append_column (sl->priv->view, col);
g_free (title);
}
}
static void
show_types (GtkInspectorTreeData *sl)
show_types (GtkInspectorDataList *sl)
{
gtk_tree_view_set_model (sl->view, NULL);
sl->show_data = FALSE;
gtk_tree_view_set_model (sl->priv->view, NULL);
sl->priv->show_data = FALSE;
}
static void
show_data (GtkInspectorTreeData *sl)
show_data (GtkInspectorDataList *sl)
{
gtk_tree_view_set_model (sl->view, sl->object);
sl->show_data = TRUE;
gtk_tree_view_set_model (sl->priv->view, sl->priv->object);
sl->priv->show_data = TRUE;
}
static void
clear_view (GtkInspectorTreeData *sl)
clear_view (GtkInspectorDataList *sl)
{
gtk_tree_view_set_model (sl->view, NULL);
while (gtk_tree_view_get_n_columns (sl->view) > 0)
gtk_tree_view_remove_column (sl->view,
gtk_tree_view_get_column (sl->view, 0));
gtk_tree_view_set_model (sl->priv->view, NULL);
while (gtk_tree_view_get_n_columns (sl->priv->view) > 0)
gtk_tree_view_remove_column (sl->priv->view,
gtk_tree_view_get_column (sl->priv->view, 0));
}
void
gtk_inspector_tree_data_set_object (GtkInspectorTreeData *sl,
gtk_inspector_data_list_set_object (GtkInspectorDataList *sl,
GObject *object)
{
GtkWidget *stack;
@@ -138,8 +125,8 @@ gtk_inspector_tree_data_set_object (GtkInspectorTreeData *sl,
page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl));
clear_view (sl);
sl->object = NULL;
sl->show_data = FALSE;
sl->priv->object = NULL;
sl->priv->show_data = FALSE;
if (!GTK_IS_TREE_MODEL (object))
{
@@ -148,21 +135,21 @@ gtk_inspector_tree_data_set_object (GtkInspectorTreeData *sl,
}
title = gtk_inspector_get_object_title (object);
gtk_label_set_label (GTK_LABEL (sl->object_title), title);
gtk_label_set_label (GTK_LABEL (sl->priv->object_title), title);
g_free (title);
g_object_set (page, "visible", TRUE, NULL);
sl->object = GTK_TREE_MODEL (object);
sl->priv->object = GTK_TREE_MODEL (object);
add_columns (sl);
show_types (sl);
}
static void
toggle_show (GtkToggleButton *button,
GtkInspectorTreeData *sl)
GtkInspectorDataList *sl)
{
if (gtk_toggle_button_get_active (button) == sl->show_data)
if (gtk_toggle_button_get_active (button) == sl->priv->show_data)
return;
if (gtk_toggle_button_get_active (button))
@@ -172,16 +159,14 @@ toggle_show (GtkToggleButton *button,
}
static void
gtk_inspector_tree_data_class_init (GtkInspectorTreeDataClass *klass)
gtk_inspector_data_list_class_init (GtkInspectorDataListClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/tree-data.ui");
gtk_widget_class_bind_template_child (widget_class, GtkInspectorTreeData, view);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorTreeData, object_title);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/data-list.ui");
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorDataList, view);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorDataList, object_title);
gtk_widget_class_bind_template_callback (widget_class, toggle_show);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
}
// vim: set et sw=2 ts=2:
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2014 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 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/>.
*/
#ifndef _GTK_INSPECTOR_DATA_LIST_H_
#define _GTK_INSPECTOR_DATA_LIST_H_
#include <gtk/gtkbox.h>
#define GTK_TYPE_INSPECTOR_DATA_LIST (gtk_inspector_data_list_get_type())
#define GTK_INSPECTOR_DATA_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_DATA_LIST, GtkInspectorDataList))
#define GTK_INSPECTOR_DATA_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_INSPECTOR_DATA_LIST, GtkInspectorDataListClass))
#define GTK_INSPECTOR_IS_DATA_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_INSPECTOR_DATA_LIST))
#define GTK_INSPECTOR_IS_DATA_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_INSPECTOR_DATA_LIST))
#define GTK_INSPECTOR_DATA_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_INSPECTOR_DATA_LIST, GtkInspectorDataListClass))
typedef struct _GtkInspectorDataListPrivate GtkInspectorDataListPrivate;
typedef struct _GtkInspectorDataList
{
GtkBox parent;
GtkInspectorDataListPrivate *priv;
} GtkInspectorDataList;
typedef struct _GtkInspectorDataListClass
{
GtkBoxClass parent;
} GtkInspectorDataListClass;
G_BEGIN_DECLS
GType gtk_inspector_data_list_get_type (void);
void gtk_inspector_data_list_set_object (GtkInspectorDataList *sl,
GObject *object);
G_END_DECLS
#endif // _GTK_INSPECTOR_DATA_LIST_H_
// vim: set et sw=2 ts=2:
@@ -1,5 +1,6 @@
<interface domain="gtk40">
<template class="GtkInspectorTreeData" parent="GtkWidget">
<template class="GtkInspectorDataList" parent="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
-1
View File
@@ -728,7 +728,6 @@
<widgets>
<widget name="version_frame"/>
<widget name="gl_frame"/>
<widget name="monitor_frame"/>
<widget name="vulkan_frame"/>
<widget name="env_frame"/>
<widget name="display_frame"/>
+2 -4
View File
@@ -29,9 +29,9 @@
#include "controllers.h"
#include "css-editor.h"
#include "css-node-tree.h"
#include "data-list.h"
#include "general.h"
#include "graphdata.h"
#include "list-data.h"
#include "logs.h"
#include "magnifier.h"
#include "menu.h"
@@ -43,7 +43,6 @@
#include "shortcuts.h"
#include "size-groups.h"
#include "statistics.h"
#include "tree-data.h"
#include "visual.h"
#include "window.h"
@@ -65,8 +64,8 @@ gtk_inspector_init (void)
g_type_ensure (GTK_TYPE_INSPECTOR_CONTROLLERS);
g_type_ensure (GTK_TYPE_INSPECTOR_CSS_EDITOR);
g_type_ensure (GTK_TYPE_INSPECTOR_CSS_NODE_TREE);
g_type_ensure (GTK_TYPE_INSPECTOR_DATA_LIST);
g_type_ensure (GTK_TYPE_INSPECTOR_GENERAL);
g_type_ensure (GTK_TYPE_INSPECTOR_LIST_DATA);
g_type_ensure (GTK_TYPE_INSPECTOR_LOGS);
g_type_ensure (GTK_TYPE_MAGNIFIER);
g_type_ensure (GTK_TYPE_INSPECTOR_MAGNIFIER);
@@ -79,7 +78,6 @@ gtk_inspector_init (void)
g_type_ensure (GTK_TYPE_INSPECTOR_SHORTCUTS);
g_type_ensure (GTK_TYPE_INSPECTOR_SIZE_GROUPS);
g_type_ensure (GTK_TYPE_INSPECTOR_STATISTICS);
g_type_ensure (GTK_TYPE_INSPECTOR_TREE_DATA);
g_type_ensure (GTK_TYPE_INSPECTOR_VISUAL);
g_type_ensure (GTK_TYPE_INSPECTOR_WINDOW);
-274
View File
@@ -1,274 +0,0 @@
/*
* Copyright (c) 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 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include "list-data.h"
#include "object-tree.h"
#include "gtkcolumnview.h"
#include "gtktogglebutton.h"
#include "gtklabel.h"
#include "gtkstack.h"
#include "gtkboxlayout.h"
#include "gtkorientable.h"
#include "gtknoselection.h"
#include "gtksignallistitemfactory.h"
#include "gtklistitem.h"
struct _GtkInspectorListData
{
GtkWidget parent_instance;
GtkInspectorObjectTree *object_tree;
GListModel *object;
GtkColumnView *view;
GtkWidget *items_label;
};
struct _GtkInspectorListDataClass
{
GtkWidgetClass parent_class;
};
enum
{
PROP_0,
PROP_OBJECT_TREE,
};
G_DEFINE_TYPE (GtkInspectorListData, gtk_inspector_list_data, GTK_TYPE_WIDGET)
static void
gtk_inspector_list_data_init (GtkInspectorListData *sl)
{
gtk_widget_init_template (GTK_WIDGET (sl));
gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_widget_get_layout_manager (GTK_WIDGET (sl))),
GTK_ORIENTATION_VERTICAL);
}
void
gtk_inspector_list_data_set_object (GtkInspectorListData *sl,
GObject *object)
{
GtkWidget *stack;
GtkStackPage *page;
char *text;
GtkNoSelection *selection;
stack = gtk_widget_get_parent (GTK_WIDGET (sl));
page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl));
gtk_column_view_set_model (sl->view, NULL);
sl->object = NULL;
if (!G_IS_LIST_MODEL (object))
{
g_object_set (page, "visible", FALSE, NULL);
return;
}
text = g_strdup_printf ("%u items", g_list_model_get_n_items (G_LIST_MODEL (object)));
gtk_label_set_label (GTK_LABEL (sl->items_label), text);
g_free (text);
g_object_set (page, "visible", TRUE, NULL);
sl->object = G_LIST_MODEL (object);
selection = gtk_no_selection_new (sl->object);
gtk_column_view_set_model (sl->view, G_LIST_MODEL (selection));
g_object_unref (selection);
}
static void
setup_object (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_widget_add_css_class (label, "cell");
gtk_list_item_set_child (item, label);
}
static void
bind_object (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
gpointer obj;
char *text;
label = gtk_list_item_get_child (item);
obj = gtk_list_item_get_item (item);
text = g_strdup_printf ("%p", obj);
gtk_label_set_label (GTK_LABEL (label), text);
g_free (text);
}
static void
setup_type (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0);
gtk_widget_add_css_class (label, "cell");
gtk_list_item_set_child (item, label);
}
static void
bind_type (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *label;
gpointer obj;
label = gtk_list_item_get_child (item);
obj = gtk_list_item_get_item (item);
gtk_label_set_label (GTK_LABEL (label), G_OBJECT_TYPE_NAME (obj));
}
static void
setup_props (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
GtkWidget *button;
button = gtk_button_new_with_label ("Properties");
gtk_widget_add_css_class (button, "cell");
gtk_widget_set_halign (button, GTK_ALIGN_START);
gtk_list_item_set_child (item, button);
}
static void
object_properties (GtkWidget *button,
GtkListItem *item)
{
GtkInspectorListData *sl;
gpointer obj;
sl = GTK_INSPECTOR_LIST_DATA (gtk_widget_get_ancestor (button, GTK_TYPE_INSPECTOR_LIST_DATA));
obj = gtk_list_item_get_item (item);
g_object_set_data (G_OBJECT (sl->object_tree), "next-tab", (gpointer)"properties");
gtk_inspector_object_tree_activate_object (sl->object_tree, obj);
}
static void
bind_props (GtkSignalListItemFactory *factory,
GtkListItem *item,
GtkInspectorListData *sl)
{
g_signal_connect (gtk_list_item_get_child (item), "clicked",
G_CALLBACK (object_properties), item);
}
static void
unbind_props (GtkSignalListItemFactory *factory,
GtkListItem *item)
{
g_signal_handlers_disconnect_by_func (gtk_list_item_get_child (item), object_properties, item);
}
static void
get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object);
switch (param_id)
{
case PROP_OBJECT_TREE:
g_value_take_object (value, sl->object_tree);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object);
switch (param_id)
{
case PROP_OBJECT_TREE:
sl->object_tree = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
finalize (GObject *object)
{
GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object);
gtk_inspector_list_data_set_object (sl, NULL);
G_OBJECT_CLASS (gtk_inspector_list_data_parent_class)->finalize (object);
}
static void
gtk_inspector_list_data_class_init (GtkInspectorListDataClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = finalize;
object_class->get_property = get_property;
object_class->set_property = set_property;
g_object_class_install_property (object_class, PROP_OBJECT_TREE,
g_param_spec_object ("object-tree", "Object Tree", "Object tree",
GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/list-data.ui");
gtk_widget_class_bind_template_child (widget_class, GtkInspectorListData, view);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorListData, items_label);
gtk_widget_class_bind_template_callback (widget_class, setup_object);
gtk_widget_class_bind_template_callback (widget_class, bind_object);
gtk_widget_class_bind_template_callback (widget_class, setup_type);
gtk_widget_class_bind_template_callback (widget_class, bind_type);
gtk_widget_class_bind_template_callback (widget_class, setup_props);
gtk_widget_class_bind_template_callback (widget_class, bind_props);
gtk_widget_class_bind_template_callback (widget_class, unbind_props);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
}
// vim: set et sw=2 ts=2:
-38
View File
@@ -1,38 +0,0 @@
/*
* Copyright (c) 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 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/>.
*/
#ifndef _GTK_INSPECTOR_LIST_DATA_H_
#define _GTK_INSPECTOR_LIST_DATA_H_
#include <gtk/gtkbox.h>
#define GTK_TYPE_INSPECTOR_LIST_DATA (gtk_inspector_list_data_get_type())
G_DECLARE_FINAL_TYPE (GtkInspectorListData, gtk_inspector_list_data, GTK, INSPECTOR_LIST_DATA, GtkWidget)
typedef struct _GtkInspectorListData GtkInspectorListData;
G_BEGIN_DECLS
void gtk_inspector_list_data_set_object (GtkInspectorListData *sl,
GObject *object);
G_END_DECLS
#endif // _GTK_INSPECTOR_LIST_DATA_H_
// vim: set et sw=2 ts=2:
-68
View File
@@ -1,68 +0,0 @@
<interface domain="gtk40">
<template class="GtkInspectorListData" parent="GtkWidget">
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkLabel" id="items_label">
<property name="hexpand">1</property>
<property name="halign">end</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="vscrollbar-policy">always</property>
<child>
<object class="GtkColumnView" id="view">
<style>
<class name="list"/>
</style>
<child>
<object class="GtkColumnViewColumn">
<property name="title">Object</property>
<property name="factory">
<object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup_object"/>
<signal name="bind" handler="bind_object"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn">
<property name="title">Type</property>
<property name="factory">
<object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup_type"/>
<signal name="bind" handler="bind_type"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkColumnViewColumn">
<property name="title"></property>
<property name="expand">1</property>
<property name="factory">
<object class="GtkSignalListItemFactory">
<signal name="setup" handler="setup_props"/>
<signal name="bind" handler="bind_props"/>
<signal name="unbind" handler="unbind_props"/>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>
+1 -2
View File
@@ -6,6 +6,7 @@ inspector_sources = files(
'controllers.c',
'css-editor.c',
'css-node-tree.c',
'data-list.c',
'focusoverlay.c',
'fpsoverlay.c',
'general.c',
@@ -15,7 +16,6 @@ inspector_sources = files(
'init.c',
'inspect-button.c',
'inspectoroverlay.c',
'list-data.c',
'layoutoverlay.c',
'logs.c',
'magnifier.c',
@@ -33,7 +33,6 @@ inspector_sources = files(
'startrecording.c',
'statistics.c',
'strv-editor.c',
'tree-data.c',
'treewalk.c',
'type-info.c',
'updatesoverlay.c',
+63
View File
@@ -769,6 +769,36 @@ font_changed (GObject *object, GParamSpec *pspec, gpointer data)
pango_font_description_free (fb_font_desc);
}
static void
item_properties (GtkButton *button, GtkInspectorPropEditor *self)
{
GObject *item;
item = g_object_get_data (G_OBJECT (button), "item");
g_signal_emit (self, signals[SHOW_OBJECT], 0, item, "Item", "properties");
}
static GtkWidget *
create_row (gpointer item,
gpointer user_data)
{
GtkWidget *row, *label, *button;
char *name;
name = object_label (G_OBJECT (item), NULL);
label = gtk_label_new (name);
g_free (name);
button = gtk_button_new_with_label (_("Properties"));
g_object_set_data (G_OBJECT (button), "item", item);
g_signal_connect (button, "clicked", G_CALLBACK (item_properties), user_data);
row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
gtk_box_append (GTK_BOX (row), label);
gtk_box_append (GTK_BOX (row), button);
return row;
}
static GtkWidget *
property_editor (GObject *object,
GParamSpec *spec,
@@ -973,6 +1003,39 @@ property_editor (GObject *object,
G_CALLBACK (pointer_changed),
prop_edit, G_OBJECT (prop_edit));
}
else if (type == G_TYPE_PARAM_OBJECT &&
g_type_is_a (G_PARAM_SPEC_VALUE_TYPE (spec), G_TYPE_LIST_MODEL))
{
GtkWidget *popover;
GtkWidget *box;
GtkWidget *sw;
GListModel *model;
popover = gtk_popover_new ();
prop_edit = gtk_menu_button_new ();
gtk_menu_button_set_popover (GTK_MENU_BUTTON (prop_edit), popover);
sw = gtk_scrolled_window_new ();
gtk_popover_set_child (GTK_POPOVER (popover), sw);
g_object_set (sw,
"hexpand", TRUE,
"vexpand", TRUE,
"hscrollbar-policy", GTK_POLICY_NEVER,
"vscrollbar-policy", GTK_POLICY_NEVER,
NULL);
g_object_get (object, spec->name, &model, NULL);
if (g_list_model_get_n_items (model) >= 10)
g_object_set (prop_edit, "vscrollbar-policy", GTK_POLICY_AUTOMATIC, NULL);
box = gtk_list_box_new ();
gtk_list_box_set_selection_mode (GTK_LIST_BOX (box), GTK_SELECTION_NONE);
gtk_list_box_bind_model (GTK_LIST_BOX (box), model, create_row, self, NULL);
g_object_unref (model);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), box);
}
else if (type == G_TYPE_PARAM_OBJECT)
{
GtkWidget *label, *button;
+4 -4
View File
@@ -314,7 +314,7 @@ setup_name_cb (GtkSignalListItemFactory *factory,
label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_list_item_set_child (list_item, label);
gtk_widget_add_css_class (label, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
}
static void
@@ -339,7 +339,7 @@ setup_type_cb (GtkSignalListItemFactory *factory,
label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_list_item_set_child (list_item, label);
gtk_widget_add_css_class (label, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
}
static void
@@ -369,7 +369,7 @@ setup_origin_cb (GtkSignalListItemFactory *factory,
label = gtk_label_new (NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_list_item_set_child (list_item, label);
gtk_widget_add_css_class (label, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
}
static void
@@ -408,7 +408,7 @@ bind_value_cb (GtkSignalListItemFactory *factory,
widget = gtk_inspector_prop_editor_new (object, name, NULL);
g_signal_connect (widget, "show-object", G_CALLBACK (show_object), data);
gtk_list_item_set_child (list_item, widget);
gtk_widget_add_css_class (widget, "cell");
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "cell");
}
static void
+83 -17
View File
@@ -22,10 +22,9 @@
#include <gtk/gtkbinlayout.h>
#include <gtk/gtkbox.h>
#include <gtk/gtkfilechooserdialog.h>
#include <gtk/gtksignallistitemfactory.h>
#include <gtk/gtkfunctionslistitemfactory.h>
#include <gtk/gtklabel.h>
#include <gtk/gtklistbox.h>
#include <gtk/gtklistitem.h>
#include <gtk/gtklistview.h>
#include <gtk/gtkliststore.h>
#include <gtk/gtkmessagedialog.h>
@@ -303,8 +302,8 @@ node_name (GskRenderNode *node)
}
static void
setup_widget_for_render_node (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
setup_widget_for_render_node (GtkListItem *list_item,
gpointer unused)
{
GtkWidget *expander, *box, *child;
@@ -325,8 +324,8 @@ setup_widget_for_render_node (GtkSignalListItemFactory *factory,
}
static void
bind_widget_for_render_node (GtkSignalListItemFactory *factory,
GtkListItem *list_item)
bind_widget_for_render_node (GtkListItem *list_item,
gpointer unused)
{
GdkPaintable *paintable;
GskRenderNode *node;
@@ -385,6 +384,8 @@ recordings_list_row_selected (GtkListBox *box,
(gpointer[1]) { paintable },
1);
g_object_unref (paintable);
g_print ("%u render nodes\n", g_list_model_get_n_items (G_LIST_MODEL (priv->render_node_model)));
}
else
{
@@ -403,9 +404,9 @@ get_color_texture (const GdkRGBA *color)
guchar pixel[4];
guchar *data;
GBytes *bytes;
int width = 30;
int height = 30;
int i;
gint width = 30;
gint height = 30;
gint i;
pixel[0] = round (color->red * 255);
pixel[1] = round (color->green * 255);
@@ -948,7 +949,7 @@ render_node_list_selection_changed (GtkListBox *list,
static void
render_node_save_response (GtkWidget *dialog,
int response,
gint response,
GskRenderNode *node)
{
gtk_widget_hide (dialog);
@@ -1017,33 +1018,83 @@ render_node_save (GtkButton *button,
gtk_widget_show (dialog);
}
static char *
format_timespan (gint64 timespan)
{
if (ABS (timespan) < G_TIME_SPAN_MILLISECOND)
return g_strdup_printf ("%fus", (double) timespan);
else if (ABS (timespan) < 10 * G_TIME_SPAN_MILLISECOND)
return g_strdup_printf ("%.1fs", (double) timespan / G_TIME_SPAN_MILLISECOND);
else if (ABS (timespan) < G_TIME_SPAN_SECOND)
return g_strdup_printf ("%.0fms", (double) timespan / G_TIME_SPAN_MILLISECOND);
else if (ABS (timespan) < 10 * G_TIME_SPAN_SECOND)
return g_strdup_printf ("%.1fs", (double) timespan / G_TIME_SPAN_SECOND);
else
return g_strdup_printf ("%.0fs", (double) timespan / G_TIME_SPAN_SECOND);
}
static GtkWidget *
gtk_inspector_recorder_recordings_list_create_widget (gpointer item,
gpointer user_data)
{
GtkInspectorRecorder *recorder = GTK_INSPECTOR_RECORDER (user_data);
GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
GtkInspectorRecording *recording = GTK_INSPECTOR_RECORDING (item);
GtkWidget *widget;
if (GTK_INSPECTOR_IS_RENDER_RECORDING (recording))
{
GtkInspectorRecording *previous = NULL;
char *time_str, *str;
const char *render_str;
cairo_region_t *region;
GtkWidget *hbox, *label, *button;
guint i;
widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_append (GTK_BOX (widget), hbox);
for (i = 0; i < g_list_model_get_n_items (priv->recordings); i++)
{
GtkInspectorRecording *r = g_list_model_get_item (priv->recordings, i);
g_object_unref (r);
if (r == recording)
break;
if (GTK_INSPECTOR_IS_RENDER_RECORDING (r))
previous = r;
else if (GTK_INSPECTOR_IS_START_RECORDING (r))
previous = NULL;
}
region = cairo_region_create_rectangle (
gtk_inspector_render_recording_get_area (GTK_INSPECTOR_RENDER_RECORDING (recording)));
cairo_region_subtract (region,
gtk_inspector_render_recording_get_clip_region (GTK_INSPECTOR_RENDER_RECORDING (recording)));
if (cairo_region_is_empty (region))
render_str = "Full Render";
else
render_str = "Partial Render";
cairo_region_destroy (region);
label = gtk_label_new ("<b>Frame</b>");
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
if (previous)
{
time_str = format_timespan (gtk_inspector_recording_get_timestamp (recording) -
gtk_inspector_recording_get_timestamp (previous));
str = g_strdup_printf ("<b>%s</b>\n+%s", render_str, time_str);
g_free (time_str);
}
else
{
str = g_strdup_printf ("<b>%s</b>\n", render_str);
}
label = gtk_label_new (str);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
g_free (str);
gtk_box_append (GTK_BOX (hbox), label);
button = gtk_toggle_button_new ();
@@ -1240,10 +1291,9 @@ gtk_inspector_recorder_init (GtkInspectorRecorder *recorder)
priv->render_node_selection = gtk_single_selection_new (G_LIST_MODEL (priv->render_node_model));
g_signal_connect (priv->render_node_selection, "notify::selected-item", G_CALLBACK (render_node_list_selection_changed), recorder);
factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup_widget_for_render_node), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind_widget_for_render_node), NULL);
factory = gtk_functions_list_item_factory_new (setup_widget_for_render_node,
bind_widget_for_render_node,
NULL, NULL);
gtk_list_view_set_factory (GTK_LIST_VIEW (priv->render_node_list), factory);
g_object_unref (factory);
gtk_list_view_set_model (GTK_LIST_VIEW (priv->render_node_list),
@@ -1259,8 +1309,24 @@ gtk_inspector_recorder_add_recording (GtkInspectorRecorder *recorder,
GtkInspectorRecording *recording)
{
GtkInspectorRecorderPrivate *priv = gtk_inspector_recorder_get_instance_private (recorder);
guint count;
GtkListBoxRow *selected_row;
gboolean should_select_new_row;
count = g_list_model_get_n_items (priv->recordings);
selected_row = gtk_list_box_get_selected_row (GTK_LIST_BOX (priv->recordings_list));
if (count == 0 || selected_row == NULL)
should_select_new_row = TRUE;
else
should_select_new_row = (gtk_list_box_row_get_index (selected_row) == count - 1);
g_list_store_append (G_LIST_STORE (priv->recordings), recording);
if (should_select_new_row)
{
gtk_list_box_select_row (GTK_LIST_BOX (priv->recordings_list),
gtk_list_box_get_row_at_index (GTK_LIST_BOX (priv->recordings_list), count));
}
}
void
-39
View File
@@ -1,39 +0,0 @@
/*
* Copyright (c) 2014, 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 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/>.
*/
#ifndef _GTK_INSPECTOR_TREE_DATA_H_
#define _GTK_INSPECTOR_TREE_DATA_H_
#include <gtk/gtkwidget.h>
#define GTK_TYPE_INSPECTOR_TREE_DATA (gtk_inspector_tree_data_get_type ())
#define GTK_INSPECTOR_TREE_DATA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_INSPECTOR_TREE_DATA, GtkInspectorTreeData))
#define GTK_INSPECTOR_IS_TREE_DATA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_INSPECTOR_TREE_DATA))
typedef struct _GtkInspectorTreeData GtkInspectorTreeData;
G_BEGIN_DECLS
GType gtk_inspector_tree_data_get_type (void) G_GNUC_CONST;
void gtk_inspector_tree_data_set_object (GtkInspectorTreeData *sl,
GObject *object);
G_END_DECLS
#endif // _GTK_INSPECTOR_TREE_DATA_H_
// vim: set et sw=2 ts=2:
+3 -6
View File
@@ -35,14 +35,13 @@
#include "css-node-tree.h"
#include "object-tree.h"
#include "size-groups.h"
#include "data-list.h"
#include "actions.h"
#include "shortcuts.h"
#include "list-data.h"
#include "menu.h"
#include "misc-info.h"
#include "magnifier.h"
#include "recorder.h"
#include "tree-data.h"
#include "visual.h"
#include "general.h"
#include "logs.h"
@@ -101,8 +100,7 @@ set_selected_object (GtkInspectorWindow *iw,
gtk_inspector_misc_info_set_object (GTK_INSPECTOR_MISC_INFO (iw->misc_info), selected);
gtk_inspector_css_node_tree_set_object (GTK_INSPECTOR_CSS_NODE_TREE (iw->widget_css_node_tree), selected);
gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected);
gtk_inspector_tree_data_set_object (GTK_INSPECTOR_TREE_DATA (iw->tree_data), selected);
gtk_inspector_list_data_set_object (GTK_INSPECTOR_LIST_DATA (iw->list_data), selected);
gtk_inspector_data_list_set_object (GTK_INSPECTOR_DATA_LIST (iw->data_list), selected);
gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected);
gtk_inspector_shortcuts_set_object (GTK_INSPECTOR_SHORTCUTS (iw->shortcuts), selected);
gtk_inspector_menu_set_object (GTK_INSPECTOR_MENU (iw->menu), selected);
@@ -447,8 +445,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, widget_recorder);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_title);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, tree_data);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, list_data);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, data_list);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, actions);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, shortcuts);
gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, menu);
+1 -2
View File
@@ -64,8 +64,7 @@ typedef struct
GtkWidget *widget_recorder;
GtkWidget *object_hierarchy;
GtkWidget *size_groups;
GtkWidget *tree_data;
GtkWidget *list_data;
GtkWidget *data_list;
GtkWidget *actions;
GtkWidget *shortcuts;
GtkWidget *menu;
+2 -12
View File
@@ -12,6 +12,7 @@
<property name="default-width">800</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="show-title-buttons">1</property>
<child>
<object class="GtkStack" id="button_stack">
<property name="visible-child-name" bind-source="top_stack" bind-property="visible-child-name"/>
@@ -404,18 +405,7 @@
<property name="name">data</property>
<property name="title" translatable="yes">Data</property>
<property name="child">
<object class="GtkInspectorTreeData" id="tree_data"/>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">list-data</property>
<property name="title" translatable="yes">Data</property>
<property name="child">
<object class="GtkInspectorListData" id="list_data">
<property name="object-tree">object_tree</property>
</object>
<object class="GtkInspectorDataList" id="data_list"/>
</property>
</object>
</child>
+2 -2
View File
@@ -253,6 +253,7 @@ gtk_public_sources = files([
'gtkfontchooserutils.c',
'gtkfontchooserwidget.c',
'gtkframe.c',
'gtkfunctionslistitemfactory.c',
'gtkgesture.c',
'gtkgesturedrag.c',
'gtkgesturelongpress.c',
@@ -348,7 +349,6 @@ gtk_public_sources = files([
'gtkscrolledwindow.c',
'gtksearchbar.c',
'gtksearchentry.c',
'gtkselectionfiltermodel.c',
'gtkselectionmodel.c',
'gtkseparator.c',
'gtksettings.c',
@@ -537,6 +537,7 @@ gtk_public_headers = files([
'gtkfontchooserdialog.h',
'gtkfontchooserwidget.h',
'gtkframe.h',
'gtkfunctionslistitemfactory.h',
'gtkgesture.h',
'gtkgesturedrag.h',
'gtkgesturelongpress.h',
@@ -618,7 +619,6 @@ gtk_public_headers = files([
'gtkscrolledwindow.h',
'gtksearchbar.h',
'gtksearchentry.h',
'gtkselectionfiltermodel.h',
'gtkselectionmodel.h',
'gtkseparator.h',
'gtksettings.h',
+1
View File
@@ -4,6 +4,7 @@
<property name="resizable">0</property>
<child internal-child="headerbar">
<object class="GtkHeaderBar" id="headerbar1">
<property name="show-title-buttons">1</property>
<child type="title">
<object class="GtkStackSwitcher" id="stack_switcher">
<property name="visible">0</property>
+1 -3
View File
@@ -2,9 +2,7 @@
<interface domain="gtk40">
<template class="GtkAssistant" parent="GtkWindow">
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">0</property>
</object>
<object class="GtkHeaderBar" id="headerbar"/>
</child>
<child>
<object class="GtkBox" id="main_box">

Some files were not shown because too many files have changed in this diff Show More