mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-14 00:06:24 +01:00
Merge branch 'ebassi/girepository-no-gio' into 'main'
girepository: Drop libgio dependency from gdump.c See merge request GNOME/glib!3763
This commit is contained in:
commit
35c21681c1
@ -33,16 +33,73 @@
|
|||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <gio/gio.h>
|
#include <gmodule.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void
|
/* Analogue of g_output_stream_write_all(). */
|
||||||
escaped_printf (GOutputStream *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3);
|
static gboolean
|
||||||
|
write_all (FILE *out,
|
||||||
|
const void *buffer,
|
||||||
|
gsize count,
|
||||||
|
gsize *bytes_written,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
ret = fwrite (buffer, 1, count, out);
|
||||||
|
|
||||||
|
if (bytes_written != NULL)
|
||||||
|
*bytes_written = ret;
|
||||||
|
|
||||||
|
if (ret < count)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||||
|
"Failed to write to file");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Analogue of g_data_input_stream_read_line(). */
|
||||||
|
static char *
|
||||||
|
read_line (FILE *input,
|
||||||
|
size_t *len_out)
|
||||||
|
{
|
||||||
|
GByteArray *buffer = g_byte_array_new ();
|
||||||
|
const guint8 nul = '\0';
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
size_t ret;
|
||||||
|
guint8 byte;
|
||||||
|
|
||||||
|
ret = fread (&byte, 1, 1, input);
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (byte == '\n')
|
||||||
|
break;
|
||||||
|
|
||||||
|
g_byte_array_append (buffer, &byte, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_byte_array_append (buffer, &nul, 1);
|
||||||
|
|
||||||
|
if (len_out != NULL)
|
||||||
|
*len_out = buffer->len - 1; /* don’t include terminating nul */
|
||||||
|
|
||||||
|
return (char *) g_byte_array_free (buffer, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
escaped_printf (GOutputStream *out, const char *fmt, ...)
|
escaped_printf (FILE *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3);
|
||||||
|
|
||||||
|
static void
|
||||||
|
escaped_printf (FILE *out, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
va_list args;
|
va_list args;
|
||||||
@ -52,7 +109,7 @@ escaped_printf (GOutputStream *out, const char *fmt, ...)
|
|||||||
va_start (args, fmt);
|
va_start (args, fmt);
|
||||||
|
|
||||||
str = g_markup_vprintf_escaped (fmt, args);
|
str = g_markup_vprintf_escaped (fmt, args);
|
||||||
if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error))
|
if (!write_all (out, str, strlen (str), &written, &error))
|
||||||
{
|
{
|
||||||
g_critical ("failed to write to iochannel: %s", error->message);
|
g_critical ("failed to write to iochannel: %s", error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
@ -63,11 +120,11 @@ escaped_printf (GOutputStream *out, const char *fmt, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
goutput_write (GOutputStream *out, const char *str)
|
goutput_write (FILE *out, const char *str)
|
||||||
{
|
{
|
||||||
gsize written;
|
gsize written;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error))
|
if (!write_all (out, str, strlen (str), &written, &error))
|
||||||
{
|
{
|
||||||
g_critical ("failed to write to iochannel: %s", error->message);
|
g_critical ("failed to write to iochannel: %s", error->message);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
@ -86,8 +143,8 @@ invoke_get_type (GModule *self, const char *symbol, GError **error)
|
|||||||
if (!g_module_symbol (self, symbol, (void**)&sym))
|
if (!g_module_symbol (self, symbol, (void**)&sym))
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_FILE_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_FILE_ERROR_FAILED,
|
||||||
"Failed to find symbol '%s'", symbol);
|
"Failed to find symbol '%s'", symbol);
|
||||||
return G_TYPE_INVALID;
|
return G_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
@ -96,8 +153,8 @@ invoke_get_type (GModule *self, const char *symbol, GError **error)
|
|||||||
if (ret == G_TYPE_INVALID)
|
if (ret == G_TYPE_INVALID)
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_FILE_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_FILE_ERROR_FAILED,
|
||||||
"Function '%s' returned G_TYPE_INVALID", symbol);
|
"Function '%s' returned G_TYPE_INVALID", symbol);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -111,8 +168,8 @@ invoke_error_quark (GModule *self, const char *symbol, GError **error)
|
|||||||
if (!g_module_symbol (self, symbol, (void**)&sym))
|
if (!g_module_symbol (self, symbol, (void**)&sym))
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_FILE_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_FILE_ERROR_FAILED,
|
||||||
"Failed to find symbol '%s'", symbol);
|
"Failed to find symbol '%s'", symbol);
|
||||||
return G_TYPE_INVALID;
|
return G_TYPE_INVALID;
|
||||||
}
|
}
|
||||||
@ -191,10 +248,10 @@ value_to_string (const GValue *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_properties (GType type, GOutputStream *out)
|
dump_properties (GType type, FILE *out)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
guint n_properties;
|
guint n_properties = 0;
|
||||||
GParamSpec **props;
|
GParamSpec **props;
|
||||||
|
|
||||||
if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
|
if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT)
|
||||||
@ -244,7 +301,7 @@ dump_properties (GType type, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_signals (GType type, GOutputStream *out)
|
dump_signals (GType type, FILE *out)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
guint n_sigs;
|
guint n_sigs;
|
||||||
@ -296,7 +353,7 @@ dump_signals (GType type, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_object_type (GType type, const char *symbol, GOutputStream *out)
|
dump_object_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
guint n_interfaces;
|
guint n_interfaces;
|
||||||
guint i;
|
guint i;
|
||||||
@ -350,7 +407,7 @@ dump_object_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_interface_type (GType type, const char *symbol, GOutputStream *out)
|
dump_interface_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
guint n_interfaces;
|
guint n_interfaces;
|
||||||
guint i;
|
guint i;
|
||||||
@ -383,14 +440,14 @@ dump_interface_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_boxed_type (GType type, const char *symbol, GOutputStream *out)
|
dump_boxed_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
|
escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n",
|
||||||
g_type_name (type), symbol);
|
g_type_name (type), symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_flags_type (GType type, const char *symbol, GOutputStream *out)
|
dump_flags_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
GFlagsClass *klass;
|
GFlagsClass *klass;
|
||||||
@ -410,7 +467,7 @@ dump_flags_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_enum_type (GType type, const char *symbol, GOutputStream *out)
|
dump_enum_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
GEnumClass *klass;
|
GEnumClass *klass;
|
||||||
@ -430,7 +487,7 @@ dump_enum_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
|
dump_fundamental_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
guint n_interfaces;
|
guint n_interfaces;
|
||||||
guint i;
|
guint i;
|
||||||
@ -484,7 +541,7 @@ dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_type (GType type, const char *symbol, GOutputStream *out)
|
dump_type (GType type, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
switch (g_type_fundamental (type))
|
switch (g_type_fundamental (type))
|
||||||
{
|
{
|
||||||
@ -513,7 +570,7 @@ dump_type (GType type, const char *symbol, GOutputStream *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_error_quark (GQuark quark, const char *symbol, GOutputStream *out)
|
dump_error_quark (GQuark quark, const char *symbol, FILE *out)
|
||||||
{
|
{
|
||||||
escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
|
escaped_printf (out, " <error-quark function=\"%s\" domain=\"%s\"/>\n",
|
||||||
symbol, g_quark_to_string (quark));
|
symbol, g_quark_to_string (quark));
|
||||||
@ -556,11 +613,8 @@ gi_repository_dump (const char *input_filename,
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
GHashTable *output_types;
|
GHashTable *output_types;
|
||||||
GFile *input_file;
|
FILE *input;
|
||||||
GFile *output_file;
|
FILE *output;
|
||||||
GFileInputStream *input;
|
|
||||||
GFileOutputStream *output;
|
|
||||||
GDataInputStream *in;
|
|
||||||
GModule *self;
|
GModule *self;
|
||||||
gboolean caught_error = FALSE;
|
gboolean caught_error = FALSE;
|
||||||
|
|
||||||
@ -568,47 +622,47 @@ gi_repository_dump (const char *input_filename,
|
|||||||
if (!self)
|
if (!self)
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_FILE_ERROR,
|
||||||
G_IO_ERROR_FAILED,
|
G_FILE_ERROR_FAILED,
|
||||||
"failed to open self: %s",
|
"failed to open self: %s",
|
||||||
g_module_error ());
|
g_module_error ());
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
input_file = g_file_new_for_path (input_filename);
|
input = fopen (input_filename, "rb");
|
||||||
output_file = g_file_new_for_path (output_filename);
|
|
||||||
|
|
||||||
input = g_file_read (input_file, NULL, error);
|
|
||||||
g_object_unref (input_file);
|
|
||||||
|
|
||||||
if (input == NULL)
|
if (input == NULL)
|
||||||
{
|
{
|
||||||
g_object_unref (output_file);
|
int saved_errno = errno;
|
||||||
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
|
||||||
|
"Failed to open ‘%s’: %s", input_filename, g_strerror (saved_errno));
|
||||||
|
|
||||||
|
g_module_close (self);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
output = g_file_replace (output_file, NULL, FALSE, 0, NULL, error);
|
output = fopen (output_filename, "wb");
|
||||||
g_object_unref (output_file);
|
|
||||||
|
|
||||||
if (output == NULL)
|
if (output == NULL)
|
||||||
{
|
{
|
||||||
g_input_stream_close (G_INPUT_STREAM (input), NULL, NULL);
|
int saved_errno = errno;
|
||||||
g_object_unref (input);
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
|
||||||
|
"Failed to open ‘%s’: %s", output_filename, g_strerror (saved_errno));
|
||||||
|
|
||||||
|
fclose (input);
|
||||||
|
g_module_close (self);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
goutput_write (G_OUTPUT_STREAM (output), "<?xml version=\"1.0\"?>\n");
|
goutput_write (output, "<?xml version=\"1.0\"?>\n");
|
||||||
goutput_write (G_OUTPUT_STREAM (output), "<dump>\n");
|
goutput_write (output, "<dump>\n");
|
||||||
|
|
||||||
output_types = g_hash_table_new (NULL, NULL);
|
output_types = g_hash_table_new (NULL, NULL);
|
||||||
|
|
||||||
in = g_data_input_stream_new (G_INPUT_STREAM (input));
|
|
||||||
g_object_unref (input);
|
|
||||||
|
|
||||||
while (TRUE)
|
while (TRUE)
|
||||||
{
|
{
|
||||||
gsize len;
|
gsize len;
|
||||||
char *line = g_data_input_stream_read_line (in, &len, NULL, NULL);
|
char *line = read_line (input, &len);
|
||||||
const char *function;
|
const char *function;
|
||||||
|
|
||||||
if (line == NULL || *line == '\0')
|
if (line == NULL || *line == '\0')
|
||||||
@ -639,7 +693,7 @@ gi_repository_dump (const char *input_filename,
|
|||||||
goto next;
|
goto next;
|
||||||
g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
|
g_hash_table_insert (output_types, (gpointer) type, (gpointer) type);
|
||||||
|
|
||||||
dump_type (type, function, G_OUTPUT_STREAM (output));
|
dump_type (type, function, output);
|
||||||
}
|
}
|
||||||
else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
|
else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0)
|
||||||
{
|
{
|
||||||
@ -655,7 +709,7 @@ gi_repository_dump (const char *input_filename,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
dump_error_quark (quark, function, G_OUTPUT_STREAM (output));
|
dump_error_quark (quark, function, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -665,18 +719,30 @@ gi_repository_dump (const char *input_filename,
|
|||||||
|
|
||||||
g_hash_table_destroy (output_types);
|
g_hash_table_destroy (output_types);
|
||||||
|
|
||||||
goutput_write (G_OUTPUT_STREAM (output), "</dump>\n");
|
goutput_write (output, "</dump>\n");
|
||||||
|
|
||||||
{
|
{
|
||||||
/* Avoid overwriting an earlier set error */
|
/* Avoid overwriting an earlier set error */
|
||||||
caught_error |= !g_input_stream_close (G_INPUT_STREAM (in), NULL,
|
if (fclose (input) != 0 && !caught_error)
|
||||||
caught_error ? NULL : error);
|
{
|
||||||
caught_error |= !g_output_stream_close (G_OUTPUT_STREAM (output), NULL,
|
int saved_errno = errno;
|
||||||
caught_error ? NULL : error);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref (in);
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
|
||||||
g_object_unref (output);
|
"Error closing input file ‘%s’: %s", input_filename,
|
||||||
|
g_strerror (saved_errno));
|
||||||
|
caught_error = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fclose (output) != 0 && !caught_error)
|
||||||
|
{
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
|
||||||
|
"Error closing output file ‘%s’: %s", output_filename,
|
||||||
|
g_strerror (saved_errno));
|
||||||
|
caught_error = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return !caught_error;
|
return !caught_error;
|
||||||
}
|
}
|
||||||
|
@ -24,31 +24,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gdump.c"
|
#include "gdump.c"
|
||||||
#ifdef G_OS_WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <io.h> /* For _get_osfhandle() */
|
|
||||||
#include <gio/gwin32outputstream.h>
|
|
||||||
#else
|
|
||||||
#include <gio/gunixoutputstream.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char **argv)
|
char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
GOutputStream *Stdout;
|
|
||||||
GModule *self;
|
GModule *self;
|
||||||
|
|
||||||
#if defined(G_OS_WIN32)
|
|
||||||
HANDLE *hnd = (HANDLE) _get_osfhandle (1);
|
|
||||||
|
|
||||||
g_return_val_if_fail (hnd && hnd != INVALID_HANDLE_VALUE, 1);
|
|
||||||
Stdout = g_win32_output_stream_new (hnd, FALSE);
|
|
||||||
#else
|
|
||||||
Stdout = g_unix_output_stream_new (1, FALSE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
self = g_module_open (NULL, 0);
|
self = g_module_open (NULL, 0);
|
||||||
|
|
||||||
for (i = 1; i < argc; i++)
|
for (i = 1; i < argc; i++)
|
||||||
@ -63,7 +46,7 @@ main (int argc,
|
|||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
dump_type (type, argv[i], Stdout);
|
dump_type (type, argv[i], stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -197,6 +197,7 @@ libgirepository = shared_library('girepository-2.0',
|
|||||||
libgirepository_dep = declare_dependency(
|
libgirepository_dep = declare_dependency(
|
||||||
link_with: libgirepository,
|
link_with: libgirepository,
|
||||||
dependencies: [libglib_dep, libgobject_dep, libgio_dep, libgmodule_dep],
|
dependencies: [libglib_dep, libgobject_dep, libgio_dep, libgmodule_dep],
|
||||||
|
sources: [gi_visibility_h],
|
||||||
include_directories: [girepoinc],
|
include_directories: [girepoinc],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -403,6 +403,26 @@ _g_object_type_init (void)
|
|||||||
#endif /* G_ENABLE_DEBUG */
|
#endif /* G_ENABLE_DEBUG */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize the global GParamSpecPool; this function needs to be
|
||||||
|
* called whenever we access the GParamSpecPool and we cannot guarantee
|
||||||
|
* that g_object_do_class_init() has been called: for instance, by the
|
||||||
|
* interface property API.
|
||||||
|
*
|
||||||
|
* To avoid yet another global lock, we use atomic pointer checks: the
|
||||||
|
* first caller of this function will win the race. Any other access to
|
||||||
|
* the GParamSpecPool is done under its own mutex.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
g_object_init_pspec_pool (void)
|
||||||
|
{
|
||||||
|
if (G_UNLIKELY (g_atomic_pointer_get (&pspec_pool) == NULL))
|
||||||
|
{
|
||||||
|
GParamSpecPool *pool = g_param_spec_pool_new (TRUE);
|
||||||
|
if (!g_atomic_pointer_compare_and_exchange (&pspec_pool, NULL, pool))
|
||||||
|
g_param_spec_pool_free (pool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_object_base_class_init (GObjectClass *class)
|
g_object_base_class_init (GObjectClass *class)
|
||||||
{
|
{
|
||||||
@ -459,7 +479,8 @@ g_object_do_class_init (GObjectClass *class)
|
|||||||
#ifndef HAVE_OPTIONAL_FLAGS
|
#ifndef HAVE_OPTIONAL_FLAGS
|
||||||
quark_in_construction = g_quark_from_static_string ("GObject-in-construction");
|
quark_in_construction = g_quark_from_static_string ("GObject-in-construction");
|
||||||
#endif
|
#endif
|
||||||
pspec_pool = g_param_spec_pool_new (TRUE);
|
|
||||||
|
g_object_init_pspec_pool ();
|
||||||
|
|
||||||
class->constructor = g_object_constructor;
|
class->constructor = g_object_constructor;
|
||||||
class->constructed = g_object_constructed;
|
class->constructed = g_object_constructed;
|
||||||
@ -525,11 +546,13 @@ install_property_internal (GType g_type,
|
|||||||
{
|
{
|
||||||
g_param_spec_ref_sink (pspec);
|
g_param_spec_ref_sink (pspec);
|
||||||
|
|
||||||
|
g_object_init_pspec_pool ();
|
||||||
|
|
||||||
if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
|
if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
|
||||||
{
|
{
|
||||||
g_critical ("When installing property: type '%s' already has a property named '%s'",
|
g_critical ("When installing property: type '%s' already has a property named '%s'",
|
||||||
g_type_name (g_type),
|
g_type_name (g_type),
|
||||||
pspec->name);
|
pspec->name);
|
||||||
g_param_spec_unref (pspec);
|
g_param_spec_unref (pspec);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -951,6 +974,8 @@ g_object_interface_find_property (gpointer g_iface,
|
|||||||
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
|
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
|
||||||
g_return_val_if_fail (property_name != NULL, NULL);
|
g_return_val_if_fail (property_name != NULL, NULL);
|
||||||
|
|
||||||
|
g_object_init_pspec_pool ();
|
||||||
|
|
||||||
return g_param_spec_pool_lookup (pspec_pool,
|
return g_param_spec_pool_lookup (pspec_pool,
|
||||||
property_name,
|
property_name,
|
||||||
iface_class->g_type,
|
iface_class->g_type,
|
||||||
@ -1076,10 +1101,10 @@ g_object_class_list_properties (GObjectClass *class,
|
|||||||
* Since: 2.4
|
* Since: 2.4
|
||||||
*
|
*
|
||||||
* Returns: (array length=n_properties_p) (transfer container): a
|
* Returns: (array length=n_properties_p) (transfer container): a
|
||||||
* pointer to an array of pointers to #GParamSpec
|
* pointer to an array of pointers to #GParamSpec
|
||||||
* structures. The paramspecs are owned by GLib, but the
|
* structures. The paramspecs are owned by GLib, but the
|
||||||
* array should be freed with g_free() when you are done with
|
* array should be freed with g_free() when you are done with
|
||||||
* it.
|
* it.
|
||||||
*/
|
*/
|
||||||
GParamSpec**
|
GParamSpec**
|
||||||
g_object_interface_list_properties (gpointer g_iface,
|
g_object_interface_list_properties (gpointer g_iface,
|
||||||
@ -1091,6 +1116,8 @@ g_object_interface_list_properties (gpointer g_iface,
|
|||||||
|
|
||||||
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
|
g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL);
|
||||||
|
|
||||||
|
g_object_init_pspec_pool ();
|
||||||
|
|
||||||
pspecs = g_param_spec_pool_list (pspec_pool,
|
pspecs = g_param_spec_pool_list (pspec_pool,
|
||||||
iface_class->g_type,
|
iface_class->g_type,
|
||||||
&n);
|
&n);
|
||||||
|
@ -994,11 +994,32 @@ g_param_spec_pool_new (gboolean type_prefixing)
|
|||||||
|
|
||||||
memcpy (&pool->mutex, &init_mutex, sizeof (init_mutex));
|
memcpy (&pool->mutex, &init_mutex, sizeof (init_mutex));
|
||||||
pool->type_prefixing = type_prefixing != FALSE;
|
pool->type_prefixing = type_prefixing != FALSE;
|
||||||
pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals);
|
pool->hash_table = g_hash_table_new_full (param_spec_pool_hash,
|
||||||
|
param_spec_pool_equals,
|
||||||
|
(GDestroyNotify) g_param_spec_unref,
|
||||||
|
NULL);
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_param_spec_pool_free:
|
||||||
|
* @pool: (transfer full): a #GParamSpecPool
|
||||||
|
*
|
||||||
|
* Frees the resources allocated by a #GParamSpecPool.
|
||||||
|
*
|
||||||
|
* Since: 2.80
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_param_spec_pool_free (GParamSpecPool *pool)
|
||||||
|
{
|
||||||
|
g_mutex_lock (&pool->mutex);
|
||||||
|
g_hash_table_unref (pool->hash_table);
|
||||||
|
g_mutex_unlock (&pool->mutex);
|
||||||
|
g_mutex_clear (&pool->mutex);
|
||||||
|
g_free (pool);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_param_spec_pool_insert:
|
* g_param_spec_pool_insert:
|
||||||
* @pool: a #GParamSpecPool.
|
* @pool: a #GParamSpecPool.
|
||||||
@ -1053,9 +1074,7 @@ g_param_spec_pool_remove (GParamSpecPool *pool,
|
|||||||
if (pool && pspec)
|
if (pool && pspec)
|
||||||
{
|
{
|
||||||
g_mutex_lock (&pool->mutex);
|
g_mutex_lock (&pool->mutex);
|
||||||
if (g_hash_table_remove (pool->hash_table, pspec))
|
if (!g_hash_table_remove (pool->hash_table, pspec))
|
||||||
g_param_spec_unref (pspec);
|
|
||||||
else
|
|
||||||
g_critical (G_STRLOC ": attempt to remove unknown pspec '%s' from pool", pspec->name);
|
g_critical (G_STRLOC ": attempt to remove unknown pspec '%s' from pool", pspec->name);
|
||||||
g_mutex_unlock (&pool->mutex);
|
g_mutex_unlock (&pool->mutex);
|
||||||
}
|
}
|
||||||
|
@ -443,7 +443,8 @@ GOBJECT_AVAILABLE_IN_ALL
|
|||||||
GParamSpec** g_param_spec_pool_list (GParamSpecPool *pool,
|
GParamSpec** g_param_spec_pool_list (GParamSpecPool *pool,
|
||||||
GType owner_type,
|
GType owner_type,
|
||||||
guint *n_pspecs_p);
|
guint *n_pspecs_p);
|
||||||
|
GOBJECT_AVAILABLE_IN_2_80
|
||||||
|
void g_param_spec_pool_free (GParamSpecPool *pool);
|
||||||
|
|
||||||
/* contracts:
|
/* contracts:
|
||||||
*
|
*
|
||||||
|
@ -83,6 +83,7 @@ gobject_tests = {
|
|||||||
'binding' : {},
|
'binding' : {},
|
||||||
'bindinggroup' : {},
|
'bindinggroup' : {},
|
||||||
'properties' : {},
|
'properties' : {},
|
||||||
|
'properties-introspection' : {},
|
||||||
'reference' : {},
|
'reference' : {},
|
||||||
'flags' : {},
|
'flags' : {},
|
||||||
'value' : {},
|
'value' : {},
|
||||||
|
@ -1624,6 +1624,23 @@ test_param_spec_custom (void)
|
|||||||
g_param_spec_unref (pspec);
|
g_param_spec_unref (pspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_param_spec_pool (void)
|
||||||
|
{
|
||||||
|
GParamSpecPool *pool = g_param_spec_pool_new (FALSE);
|
||||||
|
GParamSpec *pspec = g_param_spec_int ("int", NULL, NULL, -1, 100, -1, G_PARAM_READWRITE);
|
||||||
|
GParamSpec *check = NULL;
|
||||||
|
|
||||||
|
g_param_spec_pool_insert (pool, g_param_spec_ref_sink (pspec), G_TYPE_OBJECT);
|
||||||
|
check = g_param_spec_pool_lookup (pool, "int", G_TYPE_OBJECT, FALSE);
|
||||||
|
g_assert_true (check->owner_type == G_TYPE_OBJECT);
|
||||||
|
|
||||||
|
g_param_spec_pool_remove (pool, pspec);
|
||||||
|
g_assert_null (g_param_spec_pool_lookup (pool, "int", G_TYPE_OBJECT, FALSE));
|
||||||
|
|
||||||
|
g_param_spec_pool_free (pool);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -1680,6 +1697,7 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/paramspec/variant", test_param_spec_variant);
|
g_test_add_func ("/paramspec/variant", test_param_spec_variant);
|
||||||
g_test_add_func ("/paramspec/variant/cmp", test_param_spec_variant_cmp);
|
g_test_add_func ("/paramspec/variant/cmp", test_param_spec_variant_cmp);
|
||||||
g_test_add_func ("/paramspec/custom", test_param_spec_custom);
|
g_test_add_func ("/paramspec/custom", test_param_spec_custom);
|
||||||
|
g_test_add_func ("/paramspec/pool", test_param_spec_pool);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
114
gobject/tests/properties-introspection.c
Normal file
114
gobject/tests/properties-introspection.c
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* properties-introspection.c: Test the properties introspection API
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2023 Emmanuele Bassi
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This test is isolated so we can control the initialization of
|
||||||
|
* GObjectClass, and the global GParamSpecPool
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_DECLARE_INTERFACE (MyTestable, my_testable, MY, TESTABLE, GObject)
|
||||||
|
|
||||||
|
struct _MyTestableInterface
|
||||||
|
{
|
||||||
|
GTypeInterface g_iface;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_INTERFACE (MyTestable, my_testable, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
my_testable_default_init (MyTestableInterface *iface)
|
||||||
|
{
|
||||||
|
g_object_interface_install_property (iface,
|
||||||
|
g_param_spec_int ("check", NULL, NULL, -1, 10, 0, G_PARAM_READWRITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
properties_introspection (void)
|
||||||
|
{
|
||||||
|
g_test_summary ("Verify that introspecting properties on an interface initializes the GParamSpecPool.");
|
||||||
|
|
||||||
|
if (g_test_subprocess ())
|
||||||
|
{
|
||||||
|
gpointer klass = g_type_default_interface_ref (my_testable_get_type ());
|
||||||
|
g_assert_nonnull (klass);
|
||||||
|
|
||||||
|
GParamSpec *pspec = g_object_interface_find_property (klass, "check");
|
||||||
|
g_assert_nonnull (pspec);
|
||||||
|
|
||||||
|
g_type_default_interface_unref (klass);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT);
|
||||||
|
g_test_trap_assert_passed ();
|
||||||
|
g_test_trap_assert_stderr ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
inspect_func (gpointer data)
|
||||||
|
{
|
||||||
|
unsigned int *n_checks = data; /* (atomic) */
|
||||||
|
|
||||||
|
gpointer klass = NULL;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
klass = g_type_default_interface_ref (my_testable_get_type ());
|
||||||
|
}
|
||||||
|
while (klass == NULL);
|
||||||
|
|
||||||
|
GParamSpec *pspec = NULL;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pspec = g_object_interface_find_property (klass, "check");
|
||||||
|
}
|
||||||
|
while (pspec == NULL);
|
||||||
|
|
||||||
|
g_type_default_interface_unref (klass);
|
||||||
|
|
||||||
|
g_atomic_int_inc (n_checks);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define N_THREADS 10
|
||||||
|
|
||||||
|
static void
|
||||||
|
properties_collision (void)
|
||||||
|
{
|
||||||
|
GThread *threads[N_THREADS];
|
||||||
|
unsigned int n_checks = 0; /* (atomic) */
|
||||||
|
|
||||||
|
g_test_summary ("Verify that multiple threads create a single GParamSpecPool.");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < N_THREADS; i++)
|
||||||
|
{
|
||||||
|
char *t_name = g_strdup_printf ("inspect [%d]", i);
|
||||||
|
threads[i] = g_thread_new (t_name, inspect_func, &n_checks);
|
||||||
|
g_assert_nonnull (threads[i]);
|
||||||
|
g_free (t_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (g_atomic_int_get (&n_checks) != N_THREADS)
|
||||||
|
g_usleep (50);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < N_THREADS; i++)
|
||||||
|
g_thread_join (threads[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef N_THREADS
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_test_init (&argc, &argv, NULL);
|
||||||
|
|
||||||
|
g_test_add_func ("/properties/introspection", properties_introspection);
|
||||||
|
g_test_add_func ("/properties/collision", properties_collision);
|
||||||
|
|
||||||
|
return g_test_run ();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user