2014-06-09 16:47:45 +00:00
|
|
|
/* Gtk+ property notify tests
|
|
|
|
* Copyright (C) 2014 Matthias Clasen
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library 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
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <gtk/gtkunixprint.h>
|
2015-08-28 16:54:32 +00:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
#include "gdk/wayland/gdkwayland.h"
|
|
|
|
#endif
|
2014-06-09 16:47:45 +00:00
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
static void
|
|
|
|
assert_notifies (GObject *object,
|
|
|
|
const char *property,
|
2020-04-24 18:50:43 +00:00
|
|
|
guint counted,
|
|
|
|
guint expected)
|
2019-11-05 22:46:01 +00:00
|
|
|
{
|
|
|
|
if (expected == counted)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_test_message ("ERROR: While testing %s::%s: %u notify emissions expected, but got %u",
|
|
|
|
G_OBJECT_TYPE_NAME (object), property,
|
|
|
|
expected, counted);
|
|
|
|
g_test_fail ();
|
|
|
|
}
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
const char *name;
|
2020-07-24 13:54:49 +00:00
|
|
|
int count;
|
2014-06-09 16:47:45 +00:00
|
|
|
} NotifyData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
count_notify (GObject *obj, GParamSpec *pspec, NotifyData *data)
|
|
|
|
{
|
|
|
|
if (g_strcmp0 (data->name, pspec->name) == 0)
|
|
|
|
data->count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check that we get notifications when properties change.
|
|
|
|
* Also check that we don't emit redundant notifications for
|
|
|
|
* enum, flags, booleans, ints. We allow redundant notifications
|
|
|
|
* for strings, and floats
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
check_property (GObject *instance, GParamSpec *pspec)
|
|
|
|
{
|
2018-03-23 12:55:01 +00:00
|
|
|
g_test_message ("Checking %s:%s", G_OBJECT_TYPE_NAME (instance), pspec->name);
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
if (G_TYPE_IS_ENUM (pspec->value_type))
|
|
|
|
{
|
|
|
|
GEnumClass *class;
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2014-06-09 16:47:45 +00:00
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
2020-07-24 13:54:49 +00:00
|
|
|
int first;
|
|
|
|
int value;
|
|
|
|
int current_count;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
class = g_type_class_ref (pspec->value_type);
|
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 0);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
if (class->values[0].value == value)
|
|
|
|
first = 1;
|
|
|
|
else
|
|
|
|
first = 0;
|
|
|
|
|
|
|
|
for (i = first; i < class->n_values; i++)
|
|
|
|
{
|
|
|
|
current_count = data.count + 1;
|
|
|
|
g_object_set (instance, pspec->name, class->values[i].value, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
if (current_count == 10) /* just test a few */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
g_type_class_unref (class);
|
|
|
|
}
|
|
|
|
else if (G_TYPE_IS_FLAGS (pspec->value_type))
|
|
|
|
{
|
|
|
|
GFlagsClass *class;
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2014-06-09 16:47:45 +00:00
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
|
|
|
guint value;
|
2020-07-24 13:54:49 +00:00
|
|
|
int current_count;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
class = g_type_class_ref (pspec->value_type);
|
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 0);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
for (i = 0; i < class->n_values; i++)
|
|
|
|
{
|
|
|
|
/* some flags have a 'none' member, skip it */
|
|
|
|
if (class->values[i].value == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((value & class->values[i].value) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
value |= class->values[i].value;
|
|
|
|
current_count = data.count + 1;
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
if (current_count == 10) /* just test a few */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
g_type_class_unref (class);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_BOOLEAN)
|
|
|
|
{
|
|
|
|
NotifyData data;
|
|
|
|
gboolean value;
|
|
|
|
gulong id;
|
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 0);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
g_object_set (instance, pspec->name, 1 - value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 1);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_INT)
|
|
|
|
{
|
|
|
|
GParamSpecInt *p = G_PARAM_SPEC_INT (pspec);
|
2020-07-24 13:54:49 +00:00
|
|
|
int i;
|
2014-06-09 16:47:45 +00:00
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
2020-07-24 13:54:49 +00:00
|
|
|
int value;
|
|
|
|
int current_count;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 0);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
for (i = p->minimum; i <= p->maximum; i++)
|
|
|
|
{
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
if (value == i)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
current_count = data.count + 1;
|
|
|
|
g_object_set (instance, pspec->name, i, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
if (current_count == 10) /* just test a few */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_UINT)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
|
|
|
guint value;
|
2020-07-24 13:54:49 +00:00
|
|
|
int current_count;
|
2014-06-09 16:47:45 +00:00
|
|
|
guint minimum, maximum;
|
|
|
|
|
|
|
|
if (G_IS_PARAM_SPEC_UINT (pspec))
|
|
|
|
{
|
|
|
|
minimum = G_PARAM_SPEC_UINT (pspec)->minimum;
|
|
|
|
maximum = G_PARAM_SPEC_UINT (pspec)->maximum;
|
|
|
|
}
|
|
|
|
else /* random */
|
|
|
|
{
|
|
|
|
minimum = 0;
|
|
|
|
maximum = 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
g_object_set (instance, pspec->name, value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 0);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
for (i = minimum; i <= maximum; i++)
|
|
|
|
{
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
if (value == i)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
current_count = data.count + 1;
|
|
|
|
g_object_set (instance, pspec->name, i, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
if (current_count == 10) /* just test a few */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_STRING)
|
|
|
|
{
|
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
2020-07-24 18:40:36 +00:00
|
|
|
char *value;
|
|
|
|
char *new_value;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
/* don't check redundant notifications */
|
|
|
|
|
|
|
|
new_value = g_strconcat ("(", value, ".", value, ")", NULL);
|
|
|
|
|
|
|
|
g_object_set (instance, pspec->name, new_value, NULL);
|
|
|
|
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, 1);
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
g_free (value);
|
|
|
|
g_free (new_value);
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_DOUBLE)
|
|
|
|
{
|
|
|
|
GParamSpecDouble *p = G_PARAM_SPEC_DOUBLE (pspec);
|
|
|
|
guint i;
|
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
2020-07-24 20:32:16 +00:00
|
|
|
double value;
|
|
|
|
double new_value;
|
2020-07-24 13:54:49 +00:00
|
|
|
int current_count;
|
2020-07-24 20:32:16 +00:00
|
|
|
double delta;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
/* don't check redundant notifications */
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
|
|
|
|
if (p->maximum > 100 || p->minimum < -100)
|
|
|
|
delta = M_PI;
|
|
|
|
else
|
|
|
|
delta = (p->maximum - p->minimum) / 10.0;
|
|
|
|
|
|
|
|
new_value = p->minimum;
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
new_value += delta;
|
|
|
|
|
|
|
|
if (fabs (value - new_value) < p->epsilon)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (new_value > p->maximum)
|
|
|
|
break;
|
|
|
|
|
|
|
|
current_count = data.count + 1;
|
|
|
|
g_object_set (instance, pspec->name, new_value, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else if (pspec->value_type == G_TYPE_FLOAT)
|
|
|
|
{
|
|
|
|
GParamSpecFloat *p = G_PARAM_SPEC_FLOAT (pspec);
|
|
|
|
guint i;
|
|
|
|
NotifyData data;
|
|
|
|
gulong id;
|
2020-07-24 20:25:56 +00:00
|
|
|
float value;
|
|
|
|
float new_value;
|
2020-07-24 13:54:49 +00:00
|
|
|
int current_count;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
data.name = pspec->name;
|
|
|
|
data.count = 0;
|
|
|
|
id = g_signal_connect (instance, "notify", G_CALLBACK (count_notify), &data);
|
|
|
|
|
|
|
|
/* don't check redundant notifications */
|
|
|
|
g_object_get (instance, pspec->name, &value, NULL);
|
|
|
|
|
|
|
|
new_value = p->minimum;
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
if (fabs (value - new_value) < p->epsilon)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
current_count = data.count + 1;
|
|
|
|
new_value += (p->maximum - p->minimum) / 10.0;
|
|
|
|
|
|
|
|
if (new_value > p->maximum)
|
|
|
|
break;
|
|
|
|
|
|
|
|
g_object_set (instance, pspec->name, new_value, NULL);
|
2019-11-05 22:46:01 +00:00
|
|
|
assert_notifies (instance, pspec->name, data.count, current_count);
|
2014-06-09 16:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_handler_disconnect (instance, id);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (g_test_verbose ())
|
|
|
|
g_print ("Skipping property %s.%s of type %s\n", g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->value_type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_type (gconstpointer data)
|
|
|
|
{
|
|
|
|
GObjectClass *klass;
|
|
|
|
GObject *instance;
|
|
|
|
GParamSpec **pspecs;
|
|
|
|
guint n_pspecs, i;
|
|
|
|
GType type;
|
|
|
|
GdkDisplay *display;
|
|
|
|
|
|
|
|
type = * (GType *) data;
|
|
|
|
|
|
|
|
display = gdk_display_get_default ();
|
|
|
|
|
|
|
|
if (!G_TYPE_IS_CLASSED (type))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (G_TYPE_IS_ABSTRACT (type))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!g_type_is_a (type, G_TYPE_OBJECT))
|
|
|
|
return;
|
|
|
|
|
2020-09-12 16:01:04 +00:00
|
|
|
/* non-GTK */
|
Remove ATK
To build a better world sometimes means having to tear the old one down.
-- Alexander Pierce, "Captain America: The Winter Soldier"
ATK served us well for nearly 20 years, but the world has changed, and
GTK has changed with it. Now ATK is mostly a hindrance towards improving
the accessibility stack:
- it maps to a very specific implementation, AT-SPI, which is Linux and
Unix specific
- it requires implementing the same functionality in three different
layers of the stack: AT-SPI, ATK, and GTK
- only GTK uses it; every other Linux and Unix toolkit and application
talks to AT-SPI directly, including assistive technologies
Sadly, we cannot incrementally port GTK to a new accessibility stack;
since ATK insulates us entirely from the underlying implementation, we
cannot replace it piecemeal. Instead, we're going to remove everything
and then incrementally build on a clean slate:
- add an "accessible" interface, implemented by GTK objects directly,
which describe the accessible role and state changes for every UI
element
- add an "assistive technology context" to proxy a native accessibility
API, and assign it to every widget
- implement the AT context depending on the platform
For more information, see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2833
2020-06-16 15:41:59 +00:00
|
|
|
if (g_str_equal (g_type_name (type), "GdkPixbufSimpleAnim"))
|
2014-06-09 16:47:45 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Deprecated, not getting fixed */
|
|
|
|
if (g_str_equal (g_type_name (type), "GtkColorSelection") ||
|
2016-10-16 17:28:11 +00:00
|
|
|
g_str_equal (g_type_name (type), "GtkNumerableIcon"))
|
2014-06-09 16:47:45 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* These can't be freely constructed/destroyed */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_APPLICATION) ||
|
|
|
|
g_type_is_a (type, GDK_TYPE_PIXBUF_LOADER) ||
|
2019-03-26 18:05:48 +00:00
|
|
|
g_type_is_a (type, GTK_TYPE_LAYOUT_CHILD) ||
|
2014-06-09 16:47:45 +00:00
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
g_type_is_a (type, GTK_TYPE_PRINT_JOB) ||
|
|
|
|
#endif
|
|
|
|
g_type_is_a (type, gdk_pixbuf_simple_anim_iter_get_type ()) ||
|
|
|
|
g_str_equal (g_type_name (type), "GdkX11DeviceManagerXI2") ||
|
2016-01-03 15:34:40 +00:00
|
|
|
g_str_equal (g_type_name (type), "GdkX11DeviceManagerCore") ||
|
2014-06-09 16:47:45 +00:00
|
|
|
g_str_equal (g_type_name (type), "GdkX11Display") ||
|
2014-10-22 03:46:11 +00:00
|
|
|
g_str_equal (g_type_name (type), "GdkX11Screen") ||
|
|
|
|
g_str_equal (g_type_name (type), "GdkX11GLContext"))
|
2014-06-09 16:47:45 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* This throws a critical when the connection is dropped */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_APP_CHOOSER_DIALOG))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* These leak their GDBusConnections */
|
2020-12-02 19:15:28 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_FILE_CHOOSER_DIALOG) ||
|
2014-06-09 16:47:45 +00:00
|
|
|
g_type_is_a (type, GTK_TYPE_FILE_CHOOSER_WIDGET) ||
|
2018-01-08 19:37:45 +00:00
|
|
|
g_type_is_a (type, GTK_TYPE_FILE_CHOOSER_NATIVE))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_str_equal (g_type_name (type), "GtkPlacesSidebar"))
|
2014-06-09 16:47:45 +00:00
|
|
|
return;
|
2015-05-06 10:39:14 +00:00
|
|
|
|
|
|
|
/* These rely on a d-bus session bus */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_MOUNT_OPERATION))
|
|
|
|
return;
|
2015-08-28 16:54:32 +00:00
|
|
|
|
2020-01-14 14:20:18 +00:00
|
|
|
/* Needs a special surface */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_DRAG_ICON))
|
|
|
|
return;
|
|
|
|
|
2020-03-19 15:57:02 +00:00
|
|
|
/* these assert in constructed */
|
2020-03-20 15:19:45 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_ALTERNATIVE_TRIGGER) ||
|
|
|
|
g_type_is_a (type, GTK_TYPE_SIGNAL_ACTION) ||
|
|
|
|
g_type_is_a (type, GTK_TYPE_NAMED_ACTION))
|
2020-03-19 15:57:02 +00:00
|
|
|
return;
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
klass = g_type_class_ref (type);
|
|
|
|
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_SETTINGS))
|
2017-12-09 12:14:00 +00:00
|
|
|
instance = G_OBJECT (g_object_ref (gtk_settings_get_default ()));
|
2018-03-20 10:40:08 +00:00
|
|
|
else if (g_type_is_a (type, GDK_TYPE_SURFACE))
|
2014-06-09 16:47:45 +00:00
|
|
|
{
|
2020-07-30 21:06:59 +00:00
|
|
|
instance = G_OBJECT (g_object_ref (gdk_surface_new_toplevel (display)));
|
2014-06-09 16:47:45 +00:00
|
|
|
}
|
|
|
|
else if (g_str_equal (g_type_name (type), "GdkX11Cursor"))
|
|
|
|
instance = g_object_new (type, "display", display, NULL);
|
2017-12-27 01:05:07 +00:00
|
|
|
else if (g_str_equal (g_type_name (type), "GdkClipboard"))
|
|
|
|
instance = g_object_new (type, "display", display, NULL);
|
2018-07-14 17:02:42 +00:00
|
|
|
else if (g_str_equal (g_type_name (type), "GdkDrag"))
|
2018-05-07 15:31:26 +00:00
|
|
|
{
|
|
|
|
GdkContentFormats *formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
|
|
|
instance = g_object_new (type,
|
|
|
|
"device", gdk_seat_get_pointer (gdk_display_get_default_seat (gdk_display_get_default ())),
|
|
|
|
"formats", formats,
|
|
|
|
NULL);
|
|
|
|
gdk_content_formats_unref (formats);
|
|
|
|
}
|
2018-04-30 12:10:44 +00:00
|
|
|
else if (g_str_equal (g_type_name (type), "GdkDrop"))
|
|
|
|
{
|
|
|
|
GdkContentFormats *formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
|
|
|
|
instance = g_object_new (type,
|
|
|
|
"device", gdk_seat_get_pointer (gdk_display_get_default_seat (gdk_display_get_default ())),
|
|
|
|
"formats", formats,
|
|
|
|
NULL);
|
|
|
|
gdk_content_formats_unref (formats);
|
|
|
|
}
|
2020-11-16 19:16:53 +00:00
|
|
|
else if (g_type_is_a (type, GSK_TYPE_GL_SHADER))
|
|
|
|
{
|
|
|
|
GBytes *bytes = g_bytes_new_static ("", 0);
|
|
|
|
instance = g_object_new (type, "source", bytes, NULL);
|
|
|
|
g_bytes_unref (bytes);
|
|
|
|
}
|
2019-10-07 04:36:25 +00:00
|
|
|
else if (g_type_is_a (type, GTK_TYPE_FILTER_LIST_MODEL) ||
|
2019-10-07 04:28:28 +00:00
|
|
|
g_type_is_a (type, GTK_TYPE_NO_SELECTION) ||
|
2019-12-09 06:19:38 +00:00
|
|
|
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION) ||
|
|
|
|
g_type_is_a (type, GTK_TYPE_MULTI_SELECTION))
|
2018-08-31 03:34:18 +00:00
|
|
|
{
|
|
|
|
GListStore *list_store = g_list_store_new (G_TYPE_OBJECT);
|
|
|
|
instance = g_object_new (type,
|
|
|
|
"model", list_store,
|
|
|
|
NULL);
|
|
|
|
g_object_unref (list_store);
|
|
|
|
}
|
2020-03-29 13:01:13 +00:00
|
|
|
else if (g_type_is_a (type, GTK_TYPE_CALENDAR))
|
|
|
|
{
|
|
|
|
/* avoid day 30 and 31, since they don't exist in February */
|
|
|
|
instance = g_object_new (type,
|
|
|
|
"year", 1984,
|
|
|
|
"month", 10,
|
|
|
|
"day", 05,
|
|
|
|
NULL);
|
|
|
|
}
|
2020-03-19 15:57:02 +00:00
|
|
|
/* special casing for singletons */
|
|
|
|
else if (g_type_is_a (type, GTK_TYPE_NEVER_TRIGGER))
|
|
|
|
instance = (GObject *) g_object_ref (gtk_never_trigger_get ());
|
2020-03-20 15:19:45 +00:00
|
|
|
else if (g_type_is_a (type, GTK_TYPE_NOTHING_ACTION))
|
|
|
|
instance = (GObject *) g_object_ref (gtk_nothing_action_get ());
|
|
|
|
else if (g_type_is_a (type, GTK_TYPE_ACTIVATE_ACTION))
|
|
|
|
instance = (GObject *) g_object_ref (gtk_activate_action_get ());
|
|
|
|
else if (g_type_is_a (type, GTK_TYPE_MNEMONIC_ACTION))
|
|
|
|
instance = (GObject *) g_object_ref (gtk_mnemonic_action_get ());
|
2014-06-09 16:47:45 +00:00
|
|
|
else
|
|
|
|
instance = g_object_new (type, NULL);
|
|
|
|
|
|
|
|
if (g_type_is_a (type, G_TYPE_INITIALLY_UNOWNED))
|
|
|
|
g_object_ref_sink (instance);
|
|
|
|
|
|
|
|
pspecs = g_object_class_list_properties (klass, &n_pspecs);
|
|
|
|
for (i = 0; i < n_pspecs; ++i)
|
|
|
|
{
|
|
|
|
GParamSpec *pspec = pspecs[i];
|
|
|
|
|
|
|
|
if ((pspec->flags & G_PARAM_READABLE) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((pspec->flags & G_PARAM_WRITABLE) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) != 0)
|
|
|
|
continue;
|
|
|
|
|
2020-09-12 16:01:04 +00:00
|
|
|
/* non-GTK */
|
Remove ATK
To build a better world sometimes means having to tear the old one down.
-- Alexander Pierce, "Captain America: The Winter Soldier"
ATK served us well for nearly 20 years, but the world has changed, and
GTK has changed with it. Now ATK is mostly a hindrance towards improving
the accessibility stack:
- it maps to a very specific implementation, AT-SPI, which is Linux and
Unix specific
- it requires implementing the same functionality in three different
layers of the stack: AT-SPI, ATK, and GTK
- only GTK uses it; every other Linux and Unix toolkit and application
talks to AT-SPI directly, including assistive technologies
Sadly, we cannot incrementally port GTK to a new accessibility stack;
since ATK insulates us entirely from the underlying implementation, we
cannot replace it piecemeal. Instead, we're going to remove everything
and then incrementally build on a clean slate:
- add an "accessible" interface, implemented by GTK objects directly,
which describe the accessible role and state changes for every UI
element
- add an "assistive technology context" to proxy a native accessibility
API, and assign it to every widget
- implement the AT context depending on the platform
For more information, see: https://gitlab.gnome.org/GNOME/gtk/-/issues/2833
2020-06-16 15:41:59 +00:00
|
|
|
if (g_str_equal (g_type_name (pspec->owner_type), "GdkPixbufSimpleAnim") ||
|
2014-06-09 16:47:45 +00:00
|
|
|
g_str_equal (g_type_name (pspec->owner_type), "GMountOperation"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* set properties are best skipped */
|
|
|
|
if (pspec->value_type == G_TYPE_BOOLEAN &&
|
|
|
|
g_str_has_suffix (pspec->name, "-set"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* These are special */
|
|
|
|
if (g_type_is_a (pspec->owner_type, GTK_TYPE_WIDGET) &&
|
2020-02-26 01:57:20 +00:00
|
|
|
(g_str_equal (pspec->name, "has-focus") ||
|
|
|
|
g_str_equal (pspec->name, "has-default") ||
|
2014-06-09 16:47:45 +00:00
|
|
|
g_str_equal (pspec->name, "is-focus") ||
|
|
|
|
g_str_equal (pspec->name, "hexpand") ||
|
2020-12-07 21:41:36 +00:00
|
|
|
g_str_equal (pspec->name, "vexpand") ||
|
|
|
|
g_str_equal (pspec->name, "visible")))
|
2020-02-26 01:57:20 +00:00
|
|
|
continue;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
2020-07-26 19:27:39 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_ACCESSIBLE) &&
|
|
|
|
g_str_equal (pspec->name, "accessible-role"))
|
|
|
|
continue;
|
|
|
|
|
2015-12-04 18:17:37 +00:00
|
|
|
if (pspec->owner_type == GTK_TYPE_ENTRY &&
|
|
|
|
g_str_equal (pspec->name, "im-module"))
|
|
|
|
continue;
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
if (type == GTK_TYPE_SETTINGS)
|
|
|
|
continue;
|
|
|
|
|
2014-09-04 02:41:56 +00:00
|
|
|
if (g_type_is_a (pspec->owner_type, GTK_TYPE_ENTRY_COMPLETION) &&
|
|
|
|
g_str_equal (pspec->name, "text-column"))
|
|
|
|
continue;
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
if (g_type_is_a (pspec->owner_type, GTK_TYPE_COLOR_CHOOSER) &&
|
|
|
|
g_str_equal (pspec->name, "show-editor"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (g_type_is_a (pspec->owner_type, GTK_TYPE_NOTEBOOK) &&
|
|
|
|
g_str_equal (pspec->name, "page"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Too many special cases involving -set properties */
|
|
|
|
if (g_str_equal (g_type_name (pspec->owner_type), "GtkCellRendererText") ||
|
|
|
|
g_str_equal (g_type_name (pspec->owner_type), "GtkTextTag"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Most things assume a model is set */
|
|
|
|
if (g_str_equal (g_type_name (pspec->owner_type), "GtkComboBox"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Can only be set on unmapped windows */
|
|
|
|
if (pspec->owner_type == GTK_TYPE_WINDOW &&
|
|
|
|
g_str_equal (pspec->name, "type-hint"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Special restrictions on allowed values */
|
|
|
|
if (pspec->owner_type == GTK_TYPE_COMBO_BOX &&
|
2019-01-24 03:51:48 +00:00
|
|
|
(g_str_equal (pspec->name, "id-column") ||
|
2014-06-09 16:47:45 +00:00
|
|
|
g_str_equal (pspec->name, "active-id") ||
|
|
|
|
g_str_equal (pspec->name, "entry-text-column")))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_ENTRY_COMPLETION &&
|
|
|
|
g_str_equal (pspec->name, "text-column"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_PRINT_OPERATION &&
|
|
|
|
(g_str_equal (pspec->name, "current-page") ||
|
|
|
|
g_str_equal (pspec->name, "n-pages")))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_RANGE &&
|
|
|
|
g_str_equal (pspec->name, "fill-level"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_SPIN_BUTTON &&
|
|
|
|
g_str_equal (pspec->name, "value"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_STACK &&
|
|
|
|
g_str_equal (pspec->name, "visible-child-name"))
|
|
|
|
continue;
|
|
|
|
|
2019-02-08 14:04:08 +00:00
|
|
|
if (pspec->owner_type == GTK_TYPE_STACK_PAGE && /* Can't change position without a stack */
|
|
|
|
g_str_equal (pspec->name, "position"))
|
|
|
|
continue;
|
|
|
|
|
2019-05-18 14:22:29 +00:00
|
|
|
/* Can't realize a popover without a parent */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_POPOVER) &&
|
|
|
|
g_str_equal (pspec->name, "visible"))
|
|
|
|
continue;
|
|
|
|
|
2014-11-23 23:29:04 +00:00
|
|
|
if (pspec->owner_type == GTK_TYPE_POPOVER_MENU &&
|
|
|
|
g_str_equal (pspec->name, "visible-submenu"))
|
|
|
|
continue;
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
if (pspec->owner_type == GTK_TYPE_TEXT_VIEW &&
|
|
|
|
g_str_equal (pspec->name, "im-module"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_TREE_SELECTION &&
|
|
|
|
g_str_equal (pspec->name, "mode")) /* requires a treeview */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (pspec->owner_type == GTK_TYPE_TREE_VIEW &&
|
|
|
|
g_str_equal (pspec->name, "headers-clickable")) /* requires columns */
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* This one has a special-purpose default value */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_DIALOG) &&
|
|
|
|
g_str_equal (pspec->name, "use-header-bar"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_ASSISTANT) &&
|
|
|
|
g_str_equal (pspec->name, "use-header-bar"))
|
|
|
|
continue;
|
|
|
|
|
2015-10-27 17:26:50 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_SHORTCUTS_SHORTCUT) &&
|
|
|
|
g_str_equal (pspec->name, "accelerator"))
|
|
|
|
continue;
|
|
|
|
|
2016-08-03 03:59:34 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_SHORTCUT_LABEL) &&
|
|
|
|
g_str_equal (pspec->name, "accelerator"))
|
|
|
|
continue;
|
|
|
|
|
2016-04-26 03:08:39 +00:00
|
|
|
if (g_type_is_a (type, GTK_TYPE_FONT_CHOOSER) &&
|
|
|
|
g_str_equal (pspec->name, "font"))
|
|
|
|
continue;
|
|
|
|
|
2016-06-08 13:03:12 +00:00
|
|
|
/* these depend on the min-content- properties in a way that breaks our test */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_SCROLLED_WINDOW) &&
|
2016-06-08 13:20:02 +00:00
|
|
|
(g_str_equal (pspec->name, "max-content-width") ||
|
|
|
|
g_str_equal (pspec->name, "max-content-height")))
|
2016-06-08 13:03:12 +00:00
|
|
|
continue;
|
|
|
|
|
2018-09-01 02:59:06 +00:00
|
|
|
/* expanding only works if rows are expandable */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_TREE_LIST_ROW) &&
|
|
|
|
g_str_equal (pspec->name, "expanded"))
|
|
|
|
continue;
|
|
|
|
|
2019-02-10 03:54:37 +00:00
|
|
|
/* can't select items without an underlying, populated model */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION) &&
|
|
|
|
(g_str_equal (pspec->name, "selected") ||
|
|
|
|
g_str_equal (pspec->name, "selected-item")))
|
|
|
|
continue;
|
|
|
|
|
2019-12-09 01:22:06 +00:00
|
|
|
/* can't select items without an underlying, populated model */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_DROP_DOWN) &&
|
|
|
|
g_str_equal (pspec->name, "selected"))
|
|
|
|
continue;
|
|
|
|
|
2019-02-21 05:29:09 +00:00
|
|
|
/* can't set position without a notebook */
|
|
|
|
if (g_type_is_a (type, GTK_TYPE_NOTEBOOK_PAGE) &&
|
|
|
|
g_str_equal (pspec->name, "position"))
|
|
|
|
continue;
|
|
|
|
|
2014-06-09 16:47:45 +00:00
|
|
|
if (g_test_verbose ())
|
|
|
|
g_print ("Property %s.%s\n", g_type_name (pspec->owner_type), pspec->name);
|
|
|
|
|
|
|
|
check_property (instance, pspec);
|
|
|
|
}
|
|
|
|
g_free (pspecs);
|
|
|
|
|
2018-03-20 10:40:08 +00:00
|
|
|
if (g_type_is_a (type, GDK_TYPE_SURFACE))
|
|
|
|
gdk_surface_destroy (GDK_SURFACE (instance));
|
2014-06-09 16:47:45 +00:00
|
|
|
else
|
|
|
|
g_object_unref (instance);
|
|
|
|
|
|
|
|
g_type_class_unref (klass);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (int argc, char **argv)
|
|
|
|
{
|
|
|
|
const GType *otypes;
|
|
|
|
guint i;
|
2020-07-24 13:54:49 +00:00
|
|
|
int result;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
gtk_test_init (&argc, &argv);
|
|
|
|
gtk_test_register_all_types();
|
|
|
|
|
|
|
|
otypes = gtk_test_list_all_types (NULL);
|
|
|
|
for (i = 0; otypes[i]; i++)
|
|
|
|
{
|
2020-07-24 18:40:36 +00:00
|
|
|
char *testname;
|
2014-06-09 16:47:45 +00:00
|
|
|
|
|
|
|
testname = g_strdup_printf ("/Notification/%s", g_type_name (otypes[i]));
|
|
|
|
g_test_add_data_func (testname, &otypes[i], test_type);
|
|
|
|
g_free (testname);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = g_test_run ();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|