1/* objects-finalize.c
2 * Copyright (C) 2013 Openismus GmbH
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Tristan Van Berkom <tristanvb@openismus.com>
18 */
19#include <gtk/gtk.h>
20#include <string.h>
21
22#ifdef GDK_WINDOWING_X11
23# include <gdk/x11/gdkx.h>
24#endif
25
26
27typedef GType (*GTypeGetFunc) (void);
28
29static gboolean finalized = FALSE;
30
31static gboolean
32main_loop_quit_cb (gpointer data)
33{
34 gboolean *done = data;
35
36 *done = TRUE;
37
38 g_main_context_wakeup (NULL);
39
40 g_assert_true (finalized);
41 return FALSE;
42}
43
44static void
45check_finalized (gpointer data,
46 GObject *where_the_object_was)
47{
48 gboolean *did_finalize = (gboolean *)data;
49
50 *did_finalize = TRUE;
51}
52
53static void
54test_finalize_object (gconstpointer data)
55{
56 GType test_type = GPOINTER_TO_SIZE (data);
57 GObject *object;
58 gboolean done;
59
60 if (g_str_equal (v1: g_type_name (type: test_type), v2: "GdkClipboard"))
61 object = g_object_new (object_type: test_type, first_property_name: "display", gdk_display_get_default (), NULL);
62 else if (g_str_equal (v1: g_type_name (type: test_type), v2: "GdkDrag") ||
63 g_str_equal (v1: g_type_name (type: test_type), v2: "GdkDrop"))
64 {
65 GdkContentFormats *formats = gdk_content_formats_new_for_gtype (G_TYPE_STRING);
66 object = g_object_new (object_type: test_type,
67 first_property_name: "device", gdk_seat_get_pointer (seat: gdk_display_get_default_seat (display: gdk_display_get_default ())),
68 "formats", formats,
69 NULL);
70 gdk_content_formats_unref (formats);
71 }
72 else if (g_type_is_a (type: test_type, GSK_TYPE_GL_SHADER))
73 {
74 GBytes *bytes = g_bytes_new_static (data: "", size: 0);
75 object = g_object_new (object_type: test_type, first_property_name: "source", bytes, NULL);
76 g_bytes_unref (bytes);
77 }
78 else if (g_type_is_a (type: test_type, GTK_TYPE_FILTER_LIST_MODEL) ||
79 g_type_is_a (type: test_type, GTK_TYPE_NO_SELECTION) ||
80 g_type_is_a (type: test_type, GTK_TYPE_SINGLE_SELECTION) ||
81 g_type_is_a (type: test_type, GTK_TYPE_MULTI_SELECTION))
82 {
83 GListStore *list_store = g_list_store_new (G_TYPE_OBJECT);
84 object = g_object_new (object_type: test_type,
85 first_property_name: "model", list_store,
86 NULL);
87 g_object_unref (object: list_store);
88 }
89 else if (g_type_is_a (type: test_type, GTK_TYPE_LAYOUT_CHILD))
90 {
91#if 0
92 // See https://github.com/mesonbuild/meson/issues/7515
93 char *msg = g_strdup_printf ("Skipping %s", g_type_name (test_type));
94 g_test_skip (msg);
95 g_free (msg);
96#endif
97 return;
98 }
99 else
100 object = g_object_new (object_type: test_type, NULL);
101 g_assert_true (G_IS_OBJECT (object));
102
103 /* Make sure we have the only reference */
104 if (g_object_is_floating (object))
105 g_object_ref_sink (object);
106
107 /* Assert that the object finalizes properly */
108 g_object_weak_ref (object, notify: check_finalized, data: &finalized);
109
110 /* Toplevels are owned by GTK, just tell GTK to destroy it */
111 if (GTK_IS_WINDOW (object))
112 gtk_window_destroy (GTK_WINDOW (object));
113 else
114 g_object_unref (object);
115
116 /* Even if the object did finalize, it may have left some dangerous stuff in the GMainContext */
117 done = FALSE;
118 g_timeout_add (interval: 50, function: main_loop_quit_cb, data: &done);
119 while (!done)
120 g_main_context_iteration (NULL, TRUE);
121}
122
123static gboolean
124dbind_warning_handler (const char *log_domain,
125 GLogLevelFlags log_level,
126 const char *message,
127 gpointer user_data)
128{
129 if (strcmp (s1: log_domain, s2: "dbind") == 0 &&
130 log_level == (G_LOG_LEVEL_WARNING|G_LOG_FLAG_FATAL))
131 return FALSE;
132
133 return TRUE;
134}
135
136int
137main (int argc, char **argv)
138{
139 const GType *all_types;
140 guint n_types = 0, i;
141 int result;
142 const char *display, *x_r_d;
143
144 /* These must be set before gtk_test_init */
145 g_setenv (variable: "GIO_USE_VFS", value: "local", TRUE);
146 g_setenv (variable: "GSETTINGS_BACKEND", value: "memory", TRUE);
147
148 /* g_test_dbus_up() helpfully clears these, so we have to re-set it */
149 display = g_getenv (variable: "DISPLAY");
150 x_r_d = g_getenv (variable: "XDG_RUNTIME_DIR");
151
152 if (display)
153 g_setenv (variable: "DISPLAY", value: display, TRUE);
154 if (x_r_d)
155 g_setenv (variable: "XDG_RUNTIME_DIR", value: x_r_d, TRUE);
156
157 g_test_log_set_fatal_handler (log_func: dbind_warning_handler, NULL);
158
159 /* initialize test program */
160 gtk_test_init (argcp: &argc, argvp: &argv);
161 gtk_test_register_all_types ();
162
163 all_types = gtk_test_list_all_types (n_types: &n_types);
164
165 for (i = 0; i < n_types; i++)
166 {
167 if (g_type_is_a (type: all_types[i], G_TYPE_OBJECT) &&
168 G_TYPE_IS_INSTANTIATABLE (all_types[i]) &&
169 !G_TYPE_IS_ABSTRACT (all_types[i]) &&
170#ifdef GDK_WINDOWING_X11
171 all_types[i] != GDK_TYPE_X11_SURFACE &&
172 all_types[i] != GDK_TYPE_X11_SCREEN &&
173 all_types[i] != GDK_TYPE_X11_DISPLAY &&
174 all_types[i] != GDK_TYPE_X11_DEVICE_MANAGER_XI2 &&
175 all_types[i] != GDK_TYPE_X11_GL_CONTEXT &&
176#endif
177 /* Not allowed to finalize a GdkPixbufLoader without calling gdk_pixbuf_loader_close() */
178 all_types[i] != GDK_TYPE_PIXBUF_LOADER &&
179 all_types[i] != gdk_pixbuf_simple_anim_iter_get_type() &&
180 !g_type_is_a (type: all_types[i], GTK_TYPE_SHORTCUT_TRIGGER) &&
181 !g_type_is_a (type: all_types[i], GTK_TYPE_SHORTCUT_ACTION))
182 {
183 char *test_path = g_strdup_printf (format: "/FinalizeObject/%s", g_type_name (type: all_types[i]));
184
185 g_test_add_data_func (testpath: test_path, GSIZE_TO_POINTER (all_types[i]), test_func: test_finalize_object);
186
187 g_free (mem: test_path);
188 }
189 }
190
191 result = g_test_run();
192
193 return result;
194}
195

source code of gtk/testsuite/gtk/objects-finalize.c