diff options
author | Ivan Molodetskikh <yalterz@gmail.com> | 2022-06-28 21:46:21 -0700 |
---|---|---|
committer | Ivan Molodetskikh <yalterz@gmail.com> | 2022-06-28 21:52:49 -0700 |
commit | 53f3b4b9d9488dedfaf46567da9234df0b1343fa (patch) | |
tree | 189d24d73cf1e6cafe76ce67865ffdaf87861617 /tests | |
parent | 5bb4d69720dfe44fb79667af23560d8e7ba61337 (diff) | |
download | gtk+-53f3b4b9d9488dedfaf46567da9234df0b1343fa.tar.gz |
tests: Add testdatatable
Add a GtkColumnView scrolling performance test similar to the one used
previously in https://gitlab.gnome.org/GNOME/gtk/-/issues/3334.
The test creates a table with 20 columns and 10,000 rows and scrolls it
to a random position every frame, while measuring the frame times.
There is a commandline flag to pick the cell widget between none (for
benchmarking raw column view scrolling) and various label types. There
is also a commandline switch to disable automatic scrolling in case a
manual assessment is desired. Finally, there's an argument for
controlling the number of columns.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/meson.build | 3 | ||||
-rw-r--r-- | tests/testdatatable.c | 297 |
2 files changed, 299 insertions, 1 deletions
diff --git a/tests/meson.build b/tests/meson.build index d837b5af6d..50f8e29a1b 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -116,7 +116,8 @@ gtk_tests = [ ['testtexture'], ['testwindowdrag'], ['testinhibitshortcuts'], - ['testzoom'] + ['testzoom'], + ['testdatatable', ['frame-stats.c', 'variable.c']] ] if os_unix diff --git a/tests/testdatatable.c b/tests/testdatatable.c new file mode 100644 index 0000000000..bb9f86dc4f --- /dev/null +++ b/tests/testdatatable.c @@ -0,0 +1,297 @@ +/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ + +#include <gtk/gtk.h> + +#include "frame-stats.h" + + +/* This is our dummy item for the model. */ +#define DATA_TABLE_TYPE_ITEM (data_table_item_get_type ()) +G_DECLARE_FINAL_TYPE (DataTableItem, data_table_item, DATA_TABLE, ITEM, GObject) + +struct _DataTableItem +{ + GObject parent_instance; + int data; +}; + +struct _DataTableItemClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (DataTableItem, data_table_item, G_TYPE_OBJECT) + +static void data_table_item_init (DataTableItem *item) {} + +static void data_table_item_class_init (DataTableItemClass *class) {} + +static DataTableItem * +data_table_item_new (int data) +{ + DataTableItem *item = g_object_new (DATA_TABLE_TYPE_ITEM, NULL); + item->data = data; + return item; +} + + +static void +set_adjustment_to_fraction (GtkAdjustment *adjustment, + double fraction) +{ + double upper = gtk_adjustment_get_upper (adjustment); + double lower = gtk_adjustment_get_lower (adjustment); + double page_size = gtk_adjustment_get_page_size (adjustment); + + gtk_adjustment_set_value (adjustment, + (1 - fraction) * lower + + fraction * (upper - page_size)); +} + +static gboolean +scroll_column_view (GtkWidget *column_view, + GdkFrameClock *frame_clock, + gpointer user_data) +{ + GtkAdjustment *vadjustment; + + vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (column_view)); + + set_adjustment_to_fraction (vadjustment, g_random_double ()); + + return TRUE; +} + +enum WidgetType +{ + WIDGET_TYPE_NONE, + WIDGET_TYPE_LABEL, + WIDGET_TYPE_TEXT, + WIDGET_TYPE_INSCRIPTION, +}; + +static enum WidgetType widget_type = WIDGET_TYPE_INSCRIPTION; + +static void +setup (GtkSignalListItemFactory *factory, + GObject *listitem) +{ + GtkWidget *widget; + + switch (widget_type) + { + case WIDGET_TYPE_NONE: + /* It's actually a box, just to request size similar to labels. */ + widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_size_request (widget, 50, 18); + break; + case WIDGET_TYPE_LABEL: + widget = gtk_label_new (""); + break; + case WIDGET_TYPE_TEXT: + widget = gtk_text_new (); + break; + case WIDGET_TYPE_INSCRIPTION: + widget = gtk_inscription_new (""); + gtk_inscription_set_min_chars (GTK_INSCRIPTION (widget), 6); + break; + default: + g_assert_not_reached (); + } + + gtk_list_item_set_child (GTK_LIST_ITEM (listitem), widget); +} + +static void +bind (GtkSignalListItemFactory *factory, + GObject *listitem, + gpointer name) +{ + GtkWidget *widget; + GObject *item; + + widget = gtk_list_item_get_child (GTK_LIST_ITEM (listitem)); + item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem)); + + char buffer[16] = { 0, }; + g_snprintf (buffer, + sizeof (buffer), + "%c%d", + GPOINTER_TO_INT (name), + DATA_TABLE_ITEM (item)->data); + + switch (widget_type) + { + case WIDGET_TYPE_NONE: + break; + case WIDGET_TYPE_LABEL: + gtk_label_set_label (GTK_LABEL (widget), buffer); + break; + case WIDGET_TYPE_TEXT: + gtk_editable_set_text (GTK_EDITABLE (widget), buffer); + break; + case WIDGET_TYPE_INSCRIPTION: + gtk_inscription_set_text (GTK_INSCRIPTION (widget), buffer); + break; + default: + g_assert_not_reached (); + } +} + +static gboolean +parse_widget_arg (const gchar* option_name, + const gchar* value, + gpointer data, + GError** error) +{ + if (!g_strcmp0 (value, "none")) + { + widget_type = WIDGET_TYPE_NONE; + return TRUE; + } + else if (!g_strcmp0 (value, "label")) + { + widget_type = WIDGET_TYPE_LABEL; + return TRUE; + } + else if (!g_strcmp0 (value, "text")) + { + widget_type = WIDGET_TYPE_TEXT; + return TRUE; + } + else if (!g_strcmp0 (value, "inscription")) + { + widget_type = WIDGET_TYPE_INSCRIPTION; + return TRUE; + } + else + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, + "Invalid option value"); + return FALSE; + } +} + +static gboolean no_auto_scroll = FALSE; +static gint n_columns = 20; + +static GOptionEntry options[] = { + { + "widget", + 'w', + G_OPTION_FLAG_NONE, + G_OPTION_ARG_CALLBACK, + parse_widget_arg, + "Cell item widget to use, can be one of: none, label, text, inscription", + "WIDGET" + }, + { + "no-auto-scroll", + 'n', + G_OPTION_FLAG_NONE, + G_OPTION_ARG_NONE, + &no_auto_scroll, + "Disable automatic scrolling", + NULL + }, + { + "columns", + 'c', + G_OPTION_FLAG_NONE, + G_OPTION_ARG_INT, + &n_columns, + "Column count", + "COUNT" + }, + { NULL } +}; + +static void +quit_cb (GtkWidget *widget, + gpointer data) +{ + gboolean *done = data; + + *done = TRUE; + + g_main_context_wakeup (NULL); +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + GtkWidget *scrolled_window; + GListStore *store; + int i; + GtkMultiSelection *multi_selection; + GtkWidget *column_view; + GError *error = NULL; + gboolean done = FALSE; + + GOptionContext *context = g_option_context_new (NULL); + g_option_context_add_main_entries (context, options, NULL); + frame_stats_add_options (g_option_context_get_main_group (context)); + + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_printerr ("Option parsing failed: %s\n", error->message); + return 1; + } + + gtk_init (); + + window = gtk_window_new (); + frame_stats_ensure (GTK_WINDOW (window)); + gtk_window_set_default_size (GTK_WINDOW (window), 1700, 900); + + scrolled_window = gtk_scrolled_window_new (); + gtk_window_set_child (GTK_WINDOW (window), scrolled_window); + + store = g_list_store_new (DATA_TABLE_TYPE_ITEM); + for (i = 0; i < 10000; ++i) + { + DataTableItem *item = data_table_item_new (i); + g_list_store_append (store, item); + g_object_unref (item); + } + + multi_selection = gtk_multi_selection_new (G_LIST_MODEL (store)); + column_view = gtk_column_view_new (GTK_SELECTION_MODEL (multi_selection)); + + gtk_column_view_set_show_column_separators (GTK_COLUMN_VIEW (column_view), TRUE); + gtk_column_view_set_show_row_separators (GTK_COLUMN_VIEW (column_view), TRUE); + gtk_widget_add_css_class (column_view, "data-table"); + + for (i = 0; i < MIN (n_columns, 127 - 65); ++i) + { + const char name[] = { 'A' + i, '\0' }; + + GtkListItemFactory *factory = gtk_signal_list_item_factory_new (); + g_signal_connect (factory, "setup", G_CALLBACK (setup), NULL); + g_signal_connect (factory, "bind", G_CALLBACK (bind), GINT_TO_POINTER (name[0])); + + gtk_column_view_append_column (GTK_COLUMN_VIEW (column_view), + gtk_column_view_column_new (name, factory)); + } + + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), + column_view); + + if (!no_auto_scroll) + { + gtk_widget_add_tick_callback (column_view, + scroll_column_view, + NULL, + NULL); + } + + gtk_widget_show (window); + g_signal_connect (window, "destroy", + G_CALLBACK (quit_cb), &done); + + while (!done) + g_main_context_iteration (NULL, TRUE); + + return 0; +} |