From: Tim Janik Date: Tue, 12 Dec 2000 07:32:00 +0000 (+0000) Subject: fixed dealing with collection/lcopy of NULL values. X-Git-Tag: GLIB_1_2_9PRE1~85 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;ds=sidebyside;h=e773d7dba66cf51c7d6ad7d1973ab3635e986e2e;p=platform%2Fupstream%2Fglib.git fixed dealing with collection/lcopy of NULL values. Mon Dec 11 04:44:11 2000 Tim Janik * gboxed.c: fixed dealing with collection/lcopy of NULL values. * gclosure.h: removed insane ramblings, added G_CALLBACK() a casting convenience macro. * Makefile.am: cleanups, marshaller generation rules. * gmarshal.[hc]: new files with GRuntime standard marshallers. * glib-genmarshal.c: fix log domain, support gruntime standard marshallers, suport G_TYPE_PARAM, come with extern "C" and #include gmarshal.h. * glib-genmarshal.1: reflect glib-genmarshal.c updates. * gobject.[hc]: implement object constructor. rework parameter changed notification queueing, we support queue freezes now and don't dispatch from an idle handler anymore. parameter->property rename hassle. implemented ::properties_changed and ::notify::* signals for property change notification (the later supports property names as details). added signal connection and named data properties. (g_signal_connect_object): new function to setup while_alive connections. (g_object_class_install_property): sink properties now, since they are initially floating. (g_object_steal_data): (g_object_set_data_full): (g_object_set_data): (g_object_get_data): set/get data by using g_datalist_*() functions directly. (g_object_queue_param_changed): nuked. (g_object_freeze_notify): start queueing of property changes (freeze/ thaw calls stack). (g_object_notify): announce changes of a certain property directly. (g_object_thaw_notify): process queue of property changes, therefore emitting GObject::notify::detail with detail being the changed properties names. (G_OBJECT_WARN_INVALID_PROPERTY_ID): saner macro variant of former G_WARN_INVALID_PARAM_ID(). * gparam.[hc]: param specs are now initially floating and need to be sunken with g_param_spec_sink(), support G_TYPE_PARAM values. added G_PARAM_CONSTRUCT and G_PARAM_CONSTRUCT_ONLY parameter flags, required by GObjectClass.constructor(). * gparamspecs.[hc]: added GParamSpecParam, GParamSpecPointer and GParamSpecCCallback, param specs for G_TYPE_PARAM, G_TYPE_POINTER and G_TYPE_CCALLBACK respectively. * gsignal.[hc]: cleanups. (signal_id_lookup): after walking the anchestry, try interfaces as well. (g_signal_new): new function to create signals from varargs type list. (g_signal_connect_closure): closure connection variant that works from signal name+detail. (g_signal_connect_data): c handler connection variant that works from signal name+detail. (g_signal_emit_valist): emit signal for an instance with paraneters collected from a va_list. (g_signal_emit): emit signal, taking parameters from varargs list. (g_signal_emit_by_name): same as g_signal_emit, working from signal name+detail. (signal_emit_R): return whether return_value needs to be altered. * gtype.[hc]: set log-domain to GRuntime, i'm slowly getting to all the points that need to reflect the upcoming rename. melt g_type_conforms_to() functionality into g_type_is_a(), as that is what we really want (liskov substitution principle). assorted changes to other files due to conforms_to->is_a. * gvalue.[hc]: implemented g_value_set_instance() that sets a value from an instantiatable type via the value_table's collect_value() function (based on an idea from James Henstridge ). cleanups/fixes. * gvaluetypes.[hc]: implement G_TYPE_CCALLBACK and G_TYPE_PARAM. --- diff --git a/configure.in b/configure.in index 6fd14ac..4ec48f9 100644 --- a/configure.in +++ b/configure.in @@ -109,6 +109,7 @@ AC_ARG_ENABLE(ansi, [ --enable-ansi turn on strict ansi [default=no]] , enable_ansi=no) AC_ARG_ENABLE(threads, [ --enable-threads turn on basic thread support [default=yes] ([=no] will override --with-threads)],,enable_threads=yes) +AC_ARG_ENABLE(rebuilds, [ --disable-rebuilds disable all source autogeneration rules],,enable_rebuilds=yes) if test "x$enable_threads" != "xyes"; then enable_threads=no @@ -163,6 +164,21 @@ AC_PROG_CC AM_PROG_CC_STDC AC_PROG_INSTALL +# define a MAINT-like variable REBUILD which is set if Perl +# and awk are found, so autogenerated sources can be rebuilt +AC_PROG_AWK +AC_CHECK_PROGS(PERL, perl5 perl) +# We would like indent, but don't require it. +AC_CHECK_PROG(INDENT, indent, indent) +REBUILD=\# +if test "x$enable_rebuilds" = "xyes" && \ + test -n "$PERL" && \ + $PERL -e 'exit !($] >= 5.002)' > /dev/null 2>&1 && \ + test -n "$AWK" ; then + REBUILD= +fi +AC_SUBST(REBUILD) + dnl Initialize libtool AM_PROG_LIBTOOL diff --git a/docs/reference/glib/tmpl/arrays.sgml b/docs/reference/glib/tmpl/arrays.sgml index f4eea22..bf1f0d1 100644 --- a/docs/reference/glib/tmpl/arrays.sgml +++ b/docs/reference/glib/tmpl/arrays.sgml @@ -209,25 +209,6 @@ g_array_remove_index(). @Returns: the #GArray. - - - - - -@array: -@compare_func: - - - - - - - -@array: -@compare_func: -@user_data: - - Returns the element of a #GArray at the given index. diff --git a/docs/reference/glib/tmpl/arrays_byte.sgml b/docs/reference/glib/tmpl/arrays_byte.sgml index 9d2fb83..0a454e6 100644 --- a/docs/reference/glib/tmpl/arrays_byte.sgml +++ b/docs/reference/glib/tmpl/arrays_byte.sgml @@ -123,25 +123,6 @@ g_byte_array_remove_index(). @Returns: the #GByteArray. - - - - - -@array: -@compare_func: - - - - - - - -@array: -@compare_func: -@user_data: - - Sets the size of the #GByteArray, expanding it if necessary. diff --git a/docs/reference/glib/tmpl/arrays_pointer.sgml b/docs/reference/glib/tmpl/arrays_pointer.sgml index f44d90f..fa6659a 100644 --- a/docs/reference/glib/tmpl/arrays_pointer.sgml +++ b/docs/reference/glib/tmpl/arrays_pointer.sgml @@ -156,25 +156,6 @@ g_ptr_array_remove_index(). @Returns: the pointer which was removed. - - - - - -@array: -@compare_func: - - - - - - - -@array: -@compare_func: -@user_data: - - Sets the size of the array, expanding it if necessary. diff --git a/docs/reference/glib/tmpl/caches.sgml b/docs/reference/glib/tmpl/caches.sgml index 33752e5..119b732 100644 --- a/docs/reference/glib/tmpl/caches.sgml +++ b/docs/reference/glib/tmpl/caches.sgml @@ -51,11 +51,11 @@ called by g_cache_remove() when the object is no longer needed (i.e. its reference count drops to 0). @hash_key_func: a function to create a hash value from a key. @hash_value_func: a function to create a hash value from a value. -@key_equal_func: a function to compare two keys. It should return TRUE if -the two keys are equivalent. +@key_compare_func: @Returns: a new #GCache. -@key_compare_func: +@key_equal_func: a function to compare two keys. It should return TRUE if +the two keys are equivalent. diff --git a/docs/reference/glib/tmpl/completion.sgml b/docs/reference/glib/tmpl/completion.sgml index 80500e2..6bb7681 100644 --- a/docs/reference/glib/tmpl/completion.sgml +++ b/docs/reference/glib/tmpl/completion.sgml @@ -47,7 +47,6 @@ g_completion_complete(). @func: @prefix: @cache: -@strncmp_func: @@ -71,16 +70,6 @@ This is used when you use data structures as #GCompletion items. @Returns: the string corresponding to the item. - - - - - -@s1: -@s2: -@Returns: - - Adds items to the #GCompletion. diff --git a/docs/reference/glib/tmpl/conversions.sgml b/docs/reference/glib/tmpl/conversions.sgml index 5ce9133..1253402 100644 --- a/docs/reference/glib/tmpl/conversions.sgml +++ b/docs/reference/glib/tmpl/conversions.sgml @@ -52,56 +52,15 @@ Character Set Conversion - - - - - -@to_codeset: -@from_codeset: -@Returns: - - - - - - - -@converter: -@inbuf: -@inbytes_left: -@outbuf: -@outbytes_left: -@Returns: - - - - - - - -@converter: -@Returns: - - - - - - - -@opsysstring: -@error: -@Returns: - - @opsysstring: -@error: @Returns: + +@error: @@ -110,18 +69,9 @@ Character Set Conversion @utf8string: -@error: @Returns: - - - - - - - -@utf8string: + @error: -@Returns: @@ -132,5 +82,4 @@ Character Set Conversion @G_CONVERT_ERROR_NO_CONVERSION: @G_CONVERT_ERROR_ILLEGAL_SEQUENCE: @G_CONVERT_ERROR_FAILED: -@G_CONVERT_ERROR_PARTIAL_INPUT: diff --git a/docs/reference/glib/tmpl/fileutils.sgml b/docs/reference/glib/tmpl/fileutils.sgml index a5e9037..40b2c39 100644 --- a/docs/reference/glib/tmpl/fileutils.sgml +++ b/docs/reference/glib/tmpl/fileutils.sgml @@ -93,23 +93,3 @@ File Utilities @Returns: - - - - - -@tmpl: -@Returns: - - - - - - - -@tmpl: -@name_used: -@error: -@Returns: - - diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml index debc85f..f22b1e7 100644 --- a/docs/reference/glib/tmpl/glib-unused.sgml +++ b/docs/reference/glib/tmpl/glib-unused.sgml @@ -1,24 +1,61 @@ - + -Removes a file descriptor from the list being polled. + -@fd: the #GPollFD to remove. +@context: +@text: +@text_len: +@error: +@Returns: - + - + +@source: +@callback_data: +@callback_funcs: + + + + + + +@opsysstring: +@error: @Returns: - + + + + + +@converter: +@Returns: + + + + + + + + + + + + +@source: +@can_recurse: + + @@ -40,26 +77,122 @@ the results may be needed. See #G_PRIORITY_DEFAULT, #G_PRIORITY_DEFAULT_IDLE, #G_PRIORITY_HIGH, #G_PRIORITY_HIGH_IDLE, and #G_PRIORITY_LOW. - + +@G_MARKUP_ERROR_BAD_UTF8: text being parsed was not valid UTF-8 +@G_MARKUP_ERROR_EMPTY: document contained nothing, or only whitespace +@G_MARKUP_ERROR_PARSE: document was ill-formed +@G_MARKUP_ERROR_UNKNOWN_ELEMENT: error should be set by #GMarkupParser functions; element wasn't known +@G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE: error should be set by #GMarkupParser functions; attribute wasn't known +@G_MARKUP_ERROR_INVALID_CONTENT: error should be set by #GMarkupParser functions; something was wrong with contents of the document, e.g. invalid attribute value - + -Turns the argument into a string literal by using the '#' stringizing operator. + -@x: text to convert to a literal string. +@context: +@fd: +@priority: - + - + + + + + +@init: +@len: +@Returns: + + + + + + +@ref: +@unref: +@get: + + + + + + +@array: +@compare_func: + + + + + + +@context: +@funcs: +@user_data: +@Returns: +@source_data: + + + + + + +@context: + + + + + + + + + + + + +@array: +@compare_func: + + + + + + +@context: +@max_priority: +@timeout: +@fds: +@n_fds: +@Returns: + + + + + + +@to_codeset: +@from_codeset: +@Returns: + + + + + + +@source_funcs: +@struct_size: +@Returns: + + @@ -78,17 +211,43 @@ priority are stored in the order in which they were added. type of source. @Returns: TRUE if an event source was found and removed. - + - + +@source: +@Returns: + + + + + + +@tmpl: +@Returns: + + + + + + +@context: +@Returns: + + + + + + +@source: +@fd: @@ -96,11 +255,240 @@ type of source. - + +@source: +@timeval: + + + + + + +@s1: +@s2: +@Returns: + + + + + + +@context: +@is_running: +@Returns: + + + + + + +@converter: +@inbuf: +@inbytes_left: +@outbuf: +@outbytes_left: +@Returns: + + + + + + +@source: +@Returns: + + + + + + +@array: +@compare_func: + + + + + + +@context: +@line_number: +@char_number: + + + + + + +@utf8string: +@error: +@Returns: + + + + + + +@loop: +@Returns: + + + + + + +@context: +@fd: + + + + + + +@array: +@compare_func: +@user_data: + + + + + + +@parser: +@flags: +@user_data: +@user_data_dnotify: +@Returns: + + + + + + +@source: +@Returns: + + + + + + +@thread: +@Returns: + + + + + + +@source: +@fd: + + + + + + +@key_compare_func: +@user_data: +@Returns: + + + + + + +@source: +@Returns: + + + + + + +@source: +@func: +@data: +@notify: + + + + + + +@context: +@may_block: +@Returns: + + + + + + +@context: + + + + + + +@loop: + + + + + + +@context: +@priority: +@Returns: + + + + + + +@source: +@priority: + + + + + + +@array: +@compare_func: +@user_data: + + + + + + +@list: +@compare_func: +@user_data: +@Returns: + + + + + + +@context: +@user_data: +@Returns: + + + + + + +@context: +@func: @@ -108,11 +496,71 @@ type of source. - + +@channel: +@condition: +@Returns: + + + + + + +@source: + + + + + + + + + + + + +@context: +@id: +@Returns: + + + +Removes a file descriptor from the list being polled. + + +@fd: the #GPollFD to remove. + + + + + + + + + +Turns the argument into a string literal by using the '#' stringizing operator. + + +@x: text to convert to a literal string. + + + + + + +@Returns: + + + + + + +@context: +@Returns: @@ -121,3 +569,175 @@ type of source. @Returns: + + + + + +@loop: + + + + + + + + + + + + +@array: +@compare_func: +@user_data: + + + + + + + + + + + + +@Returns: + + + +There are no flags right now + + +@G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG: + + + + + + +@list: +@compare_func: +@user_data: +@Returns: + + + + + + +@context: +@error: +@Returns: + + + + + + +@source: +@Returns: + + + + + + +@interval: +@Returns: + + + +Any of the fields in #GMarkupParser can be %NULL, in which case they +will be ignored. Except for the @error function, any of these +callbacks can set an error; in particular the +%G_MARKUP_ERROR_UNKNOWN_ELEMENT, %G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, +and %G_MARKUP_ERROR_INVALID_CONTENT errors are intended to be set +from these callbacks. If you set an error from a callback, +g_markup_parse_context_parse() will report that error back to its caller. + + +@start_element: Callback to invoke when the opening tag of an element +is seen. +@end_element: Callback to invoke when the closing tag of an element is seen +@text: Callback to invoke when some text is seen (text is always +inside an element) +@passthrough: Callback to invoke for comments and processing +instructions; if you're re-writing the parsed document, write the +passthrough text back out in the same position +@error: Callback to invoke when an error occurs + + + +Specifies the type of a function used to test two values for +equality. The function should return TRUE if both values are equal and +FALSE otherwise. + + +@a: a value. +@b: a value to compare with. +@Returns: TRUE if @a = @b; FALSE otherwise. + + + + + + +@loop: + + + + + + +@tmpl: +@name_used: +@error: +@Returns: + + + + + + + + + + + + +@context: +@max_priority: +@fds: +@n_fds: +@Returns: + + + + + + +@Returns: + + + + + + +@source: + + + + + + +@text: +@length: +@Returns: + + + + + + + diff --git a/docs/reference/glib/tmpl/hash_tables.sgml b/docs/reference/glib/tmpl/hash_tables.sgml index c638038..edbab18 100644 --- a/docs/reference/glib/tmpl/hash_tables.sgml +++ b/docs/reference/glib/tmpl/hash_tables.sgml @@ -69,15 +69,15 @@ Hash values are used to determine where keys are stored within the #GHashTable data structure. The g_direct_hash(), g_int_hash() and g_str_hash() functions are provided for some common types of keys. If hash_func is NULL, g_direct_hash() is used. +@key_compare_func: +@Returns: a new #GHashTable. + @key_equal_func: a function to check two keys for equality. This is used when looking up keys in the #GHashTable. The g_direct_equal(), g_int_equal() and g_str_equal() functions are provided for the most common types of keys. If @key_equal_func is NULL, keys are compared directly in a similar fashion to g_direct_equal(), but without the overhead of a function call. -@Returns: a new #GHashTable. - -@key_compare_func: @@ -104,18 +104,6 @@ lookup. @Returns: the hash value corresponding to the key. - - -Specifies the type of a function used to test two values for -equality. The function should return TRUE if both values are equal and -FALSE otherwise. - - -@a: a value. -@b: a value to compare with. -@Returns: TRUE if @a = @b; FALSE otherwise. - - Inserts a new key and value into a #GHashTable. diff --git a/docs/reference/glib/tmpl/iochannels.sgml b/docs/reference/glib/tmpl/iochannels.sgml index ebfdd05..1c44eb2 100644 --- a/docs/reference/glib/tmpl/iochannels.sgml +++ b/docs/reference/glib/tmpl/iochannels.sgml @@ -209,16 +209,6 @@ Decrements the reference count of a #GIOChannel. @channel: a #GIOChannel. - - - - - -@channel: -@condition: -@Returns: - - Adds the #GIOChannel into the @@ -324,6 +314,6 @@ generic way. @io_write: @io_seek: @io_close: -@io_create_watch: +@io_add_watch: @io_free: diff --git a/docs/reference/glib/tmpl/linked_lists_double.sgml b/docs/reference/glib/tmpl/linked_lists_double.sgml index 8812d8a..ab995f0 100644 --- a/docs/reference/glib/tmpl/linked_lists_double.sgml +++ b/docs/reference/glib/tmpl/linked_lists_double.sgml @@ -268,17 +268,6 @@ value if the first element comes after the second. @Returns: the start of the sorted #GList. - - - - - -@list: -@compare_func: -@user_data: -@Returns: - - Specifies the type of a comparison function used to compare two diff --git a/docs/reference/glib/tmpl/linked_lists_single.sgml b/docs/reference/glib/tmpl/linked_lists_single.sgml index 780240f..3bb1a4e 100644 --- a/docs/reference/glib/tmpl/linked_lists_single.sgml +++ b/docs/reference/glib/tmpl/linked_lists_single.sgml @@ -271,17 +271,6 @@ value if the first element comes after the second. @Returns: the start of the sorted #GList. - - - - - -@list: -@compare_func: -@user_data: -@Returns: - - Adds the second #GSList onto the end of the first #GSList. diff --git a/docs/reference/glib/tmpl/main.sgml b/docs/reference/glib/tmpl/main.sgml index 4957d02..d3feaec 100644 --- a/docs/reference/glib/tmpl/main.sgml +++ b/docs/reference/glib/tmpl/main.sgml @@ -96,6 +96,7 @@ manages all available sources of events. + @@ -108,50 +109,7 @@ of a GLib or GTK+ application. - - - - - -@context: -@is_running: -@Returns: - - - - - - - -@loop: - - - - - - - -@loop: - - - - - - - -@loop: - - - - - - - -@loop: -@Returns: - - - + Creates a new #GMainLoop for the default main loop. A compatibility macro, see g_main_loop_new(). @@ -162,7 +120,7 @@ very important since calling g_main_run() will set this to TRUE anyway. @Returns: a new #GMainLoop. - + Frees the memory allocated for the #GMainLoop. A compatibility macro, see g_main_loop_destroy(). @@ -171,7 +129,7 @@ g_main_loop_destroy(). @loop: a #GMainLoop. - + Runs a main loop until it stops running. A compatibility macro, see g_main_loop_run(). @@ -179,7 +137,7 @@ Runs a main loop until it stops running. A compatibility macro, see g_main_loop_ @loop: a #GMainLoop. - + Stops the #GMainLoop. If g_main_run() was called to run the #GMainLoop, it will now return. A compatibility macro, see g_main_loop_quit(). @@ -188,7 +146,7 @@ it will now return. A compatibility macro, see g_main_loop_quit(). @loop: a #GMainLoop. - + Checks if the main loop is running. A compatibility macro, see g_main_loop_is_running(). @@ -243,40 +201,7 @@ It is not used within GLib or GTK+. - - - - - - - - - - - -@thread: -@Returns: - - - - - - - -@Returns: - - - - - - - -@context: -@may_block: -@Returns: - - - + Runs a single iteration for the default #GMainContext. A compatibility macro, see g_main_context_iteration(). @@ -289,16 +214,7 @@ processed. @Returns: TRUE if more events are pending. - - - - - -@context: -@Returns: - - - + Checks if any events are pending for the default #GMainContext (i.e. ready to be processed). A compatibility macro, see @@ -308,100 +224,6 @@ g_main_context_pending(). @Returns: %TRUE if any events are pending. - - - - - -@context: -@id: -@Returns: - - - - - - - -@context: -@user_data: -@Returns: - - - - - - - -@context: -@funcs: -@user_data: -@Returns: - -@source_data: - - - - - - - -@context: -@priority: -@Returns: - - - - - - - -@context: -@max_priority: -@timeout: -@fds: -@n_fds: -@Returns: - - - - - - - -@context: -@max_priority: -@fds: -@n_fds: -@Returns: - - - - - - - -@context: - - - - - - - -@context: -@func: - - - - - - - -@context: -@Returns: - - Specifies the type of function passed to g_main_set_poll_func(). @@ -417,26 +239,7 @@ The semantics of the function should match those of the or -1 if an error occurred. - - - - - -@context: -@fd: -@priority: - - - - - - - -@context: -@fd: - - - + Sets the function to use for the handle polling of file descriptors for the default main context. This is a compatability macro, see @@ -446,42 +249,25 @@ g_main_context_set_poll_func() for full details. @func: the function to call to poll all file descriptors. - + - @interval: +@function: +@data: @Returns: - - - - -@interval: -@function: -@data: -@Returns: - - -@priority: +@priority: @interval: -@function: -@data: -@notify: -@Returns: - - - - - - - +@function: +@data: +@notify: @Returns: @@ -501,10 +287,10 @@ g_main_context_set_poll_func() for full details. @priority: @function: @data: -@notify: +@destroy: @Returns: -@destroy: +@notify: @@ -550,12 +336,6 @@ poll() function to indicate which events occurred. @events: @revents: - - - - - - The #GSourceFuncs struct contains a table of functions used to handle @@ -636,122 +416,20 @@ the required condition has been met, and returns TRUE if so. @dispatch: @destroy: - - - - - -@ref: -@unref: -@get: - - - - - - -@source_funcs: -@struct_size: -@Returns: - - - - - - - -@source: -@Returns: - - - - - - - -@source: - - -@source: -@context: -@Returns: - - - - - - - -@source: - - - - - - - -@source: @priority: - - - - - - - -@source: -@Returns: - - - - - - - -@source: @can_recurse: - - - - - - - -@source: -@Returns: - - - - - - - -@source: -@Returns: - - - - - - - -@source: +@funcs: +@source_data: +@user_data: +@notify: @Returns: - - - - - - - + @source: -@func: -@data: -@notify: +@context: @@ -765,43 +443,6 @@ of the above functions. @Returns: it should return FALSE if the source should be removed. - - - - - -@source: -@callback_data: -@callback_funcs: - - - - - - - -@source: -@fd: - - - - - - - -@source: -@fd: - - - - - - - -@source: -@timeval: - - diff --git a/docs/reference/glib/tmpl/markup.sgml b/docs/reference/glib/tmpl/markup.sgml index 69680e3..9c064e3 100644 --- a/docs/reference/glib/tmpl/markup.sgml +++ b/docs/reference/glib/tmpl/markup.sgml @@ -87,118 +87,3 @@ Character references - - - - - -@G_MARKUP_ERROR_BAD_UTF8: text being parsed was not valid UTF-8 -@G_MARKUP_ERROR_EMPTY: document contained nothing, or only whitespace -@G_MARKUP_ERROR_PARSE: document was ill-formed -@G_MARKUP_ERROR_UNKNOWN_ELEMENT: error should be set by #GMarkupParser functions; element wasn't known -@G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE: error should be set by #GMarkupParser functions; attribute wasn't known -@G_MARKUP_ERROR_INVALID_CONTENT: error should be set by #GMarkupParser functions; something was wrong with contents of the document, e.g. invalid attribute value - - - - - - - - - - -There are no flags right now - - -@G_MARKUP_DO_NOT_USE_THIS_UNSUPPORTED_FLAG: - - - - - - - - - -Any of the fields in #GMarkupParser can be %NULL, in which case they -will be ignored. Except for the @error function, any of these -callbacks can set an error; in particular the -%G_MARKUP_ERROR_UNKNOWN_ELEMENT, %G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, -and %G_MARKUP_ERROR_INVALID_CONTENT errors are intended to be set -from these callbacks. If you set an error from a callback, -g_markup_parse_context_parse() will report that error back to its caller. - - -@start_element: Callback to invoke when the opening tag of an element -is seen. -@end_element: Callback to invoke when the closing tag of an element is seen -@text: Callback to invoke when some text is seen (text is always -inside an element) -@passthrough: Callback to invoke for comments and processing -instructions; if you're re-writing the parsed document, write the -passthrough text back out in the same position -@error: Callback to invoke when an error occurs - - - - - - -@text: -@length: -@Returns: - - - - - - - -@context: -@error: -@Returns: - - - - - - - -@context: - - - - - - - -@context: -@line_number: -@char_number: - - - - - - - -@parser: -@flags: -@user_data: -@user_data_dnotify: -@Returns: - - - - - - - -@context: -@text: -@text_len: -@error: -@Returns: - - diff --git a/docs/reference/glib/tmpl/relations.sgml b/docs/reference/glib/tmpl/relations.sgml index 5e83181..d6bc525 100644 --- a/docs/reference/glib/tmpl/relations.sgml +++ b/docs/reference/glib/tmpl/relations.sgml @@ -83,9 +83,9 @@ Note that this must be called before any records are added to the #GRelation. @relation: a #GRelation. @field: the field to index, counting from 0. @hash_func: a function to produce a hash value from the field data. -@key_equal_func: a function to compare two values of the given field. - @key_compare_func: + +@key_equal_func: a function to compare two values of the given field. diff --git a/docs/reference/glib/tmpl/shell.sgml b/docs/reference/glib/tmpl/shell.sgml index 9e8dcdd..4774574 100644 --- a/docs/reference/glib/tmpl/shell.sgml +++ b/docs/reference/glib/tmpl/shell.sgml @@ -36,13 +36,13 @@ Shell-related Utilities @command_line: -@argcp: -@argvp: +@argc: +@argv: @error: @Returns: -@argc: -@argv: +@argcp: +@argvp: diff --git a/docs/reference/glib/tmpl/strings.sgml b/docs/reference/glib/tmpl/strings.sgml index 23bfc3b..fd4408b 100644 --- a/docs/reference/glib/tmpl/strings.sgml +++ b/docs/reference/glib/tmpl/strings.sgml @@ -45,16 +45,6 @@ Creates a new #GString, initialized with the given string. @Returns: the new #GString. - - - - - -@init: -@len: -@Returns: - - Creates a new GString, with enough space for @dfl_size characters. diff --git a/docs/reference/glib/tmpl/trees-binary.sgml b/docs/reference/glib/tmpl/trees-binary.sgml index 11ab995..104c66a 100644 --- a/docs/reference/glib/tmpl/trees-binary.sgml +++ b/docs/reference/glib/tmpl/trees-binary.sgml @@ -61,16 +61,6 @@ second. @Returns: a new #GTree. - - - - - -@key_compare_func: -@user_data: -@Returns: - - Inserts a key/value pair into a #GTree. diff --git a/gobject/ChangeLog b/gobject/ChangeLog index fde2b44..45ec974 100644 --- a/gobject/ChangeLog +++ b/gobject/ChangeLog @@ -1,3 +1,82 @@ +Mon Dec 11 04:44:11 2000 Tim Janik + + * gboxed.c: fixed dealing with collection/lcopy of NULL values. + + * gclosure.h: removed insane ramblings, added G_CALLBACK() a casting + convenience macro. + + * Makefile.am: cleanups, marshaller generation rules. + + * gmarshal.[hc]: new files with GRuntime standard marshallers. + + * glib-genmarshal.c: fix log domain, support gruntime standard + marshallers, suport G_TYPE_PARAM, come with extern "C" and + #include gmarshal.h. + + * glib-genmarshal.1: reflect glib-genmarshal.c updates. + + * gobject.[hc]: implement object constructor. rework parameter + changed notification queueing, we support queue freezes now and + don't dispatch from an idle handler anymore. + parameter->property rename hassle. + implemented ::properties_changed and ::notify::* signals for + property change notification (the later supports property names + as details). added signal connection and named data properties. + (g_signal_connect_object): new function to setup while_alive + connections. + (g_object_class_install_property): sink properties now, since they + are initially floating. + (g_object_steal_data): + (g_object_set_data_full): + (g_object_set_data): + (g_object_get_data): set/get data by using g_datalist_*() functions + directly. + (g_object_queue_param_changed): nuked. + (g_object_freeze_notify): start queueing of property changes (freeze/ + thaw calls stack). + (g_object_notify): announce changes of a certain property directly. + (g_object_thaw_notify): process queue of property changes, therefore + emitting GObject::notify::detail with detail being the changed + properties names. + (G_OBJECT_WARN_INVALID_PROPERTY_ID): saner macro variant of former + G_WARN_INVALID_PARAM_ID(). + + * gparam.[hc]: param specs are now initially floating and need to be + sunken with g_param_spec_sink(), support G_TYPE_PARAM values. + added G_PARAM_CONSTRUCT and G_PARAM_CONSTRUCT_ONLY parameter flags, + required by GObjectClass.constructor(). + + * gparamspecs.[hc]: added GParamSpecParam, GParamSpecPointer and + GParamSpecCCallback, param specs for G_TYPE_PARAM, G_TYPE_POINTER + and G_TYPE_CCALLBACK respectively. + + * gsignal.[hc]: cleanups. + (signal_id_lookup): after walking the anchestry, try interfaces as well. + (g_signal_new): new function to create signals from varargs type list. + (g_signal_connect_closure): closure connection variant that works from + signal name+detail. + (g_signal_connect_data): c handler connection variant that works from + signal name+detail. + (g_signal_emit_valist): emit signal for an instance with paraneters + collected from a va_list. + (g_signal_emit): emit signal, taking parameters from varargs list. + (g_signal_emit_by_name): same as g_signal_emit, working from + signal name+detail. + (signal_emit_R): return whether return_value needs to be altered. + + * gtype.[hc]: set log-domain to GRuntime, i'm slowly getting to all + the points that need to reflect the upcoming rename. + melt g_type_conforms_to() functionality into g_type_is_a(), as that + is what we really want (liskov substitution principle). + assorted changes to other files due to conforms_to->is_a. + + * gvalue.[hc]: implemented g_value_set_instance() that sets a value + from an instantiatable type via the value_table's collect_value() + function (based on an idea from James Henstridge ). + cleanups/fixes. + + * gvaluetypes.[hc]: implement G_TYPE_CCALLBACK and G_TYPE_PARAM. + Wed Nov 29 13:30:05 2000 Tim Janik * gsignal.c (handlers_find): fix elliots "logic fix" that dereferences diff --git a/gobject/Makefile.am b/gobject/Makefile.am index 6296bce..0c37fdf 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -1,81 +1,144 @@ -# GObject - GLib Type, Object, Parameter and Signal Library +# GRuntime - GLib Type, Object, Parameter and Signal Library # Copyright (C) 1997,98,99,2000 Tim Janik and Red Hat, Inc. # ## Process this file with automake to produce Makefile.in -INCLUDES = -I$(top_srcdir) -I$(top_builddir) @GLIB_DEBUG_FLAGS@ +INCLUDES = @STRIP_BEGIN@ \ + -DG_LOG_DOMAIN=g_log_domain_gruntime \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + @GLIB_DEBUG_FLAGS@ \ +@STRIP_END@ # libraries to compile and install lib_LTLIBRARIES = libgobject-1.3.la -# provide g_logv() domain -AM_CFLAGS = -DG_LOG_DOMAIN=g_log_domain_gobject - # libtool stuff: set version and export symbols for resolving libgobjectincludedir = $(includedir)/glib-2.0/gobject -libgobject_1_3_la_LDFLAGS = \ - -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ - -export-dynamic +libgobject_1_3_la_LDFLAGS = @STRIP_BEGIN@ \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -export-dynamic \ +@STRIP_END@ libgobject_1_3_la_LIBADD = # $(libglib) # # setup source file variables # -# GObject header files for public installation (non-generated) -gobject_public_h_sources = @STRIP_BEGIN@ \ - gboxed.h \ - gbsearcharray.h \ - gclosure.h \ - genums.h \ - gobject.h \ - gparam.h \ - gparamspecs.h \ - gsignal.h \ - gtype.h \ - gtypemodule.h \ - gtypeplugin.h \ - gvalue.h \ - gvaluecollector.h \ - gvaluetypes.h \ +# GRuntime header files for public installation (non-generated) +gruntime_public_h_sources = @STRIP_BEGIN@ \ + gboxed.h \ + gbsearcharray.h \ + gclosure.h \ + genums.h \ + gobject.h \ + gparam.h \ + gparamspecs.h \ + gsignal.h \ + gtype.h \ + gtypemodule.h \ + gtypeplugin.h \ + gvalue.h \ + gvaluecollector.h \ + gvaluetypes.h \ @STRIP_END@ - -# private GObject header files -gobject_private_h_sources = - -# GObject C sources to build the library from -gobject_c_sources = @STRIP_BEGIN@ \ - gboxed.c \ - gbsearcharray.c \ - gclosure.c \ - genums.c \ - gobject.c \ - gparam.c \ - gparamspecs.c \ - gsignal.c \ - gtype.c \ - gtypemodule.c \ - gtypeplugin.c \ - gvalue.c \ - gvaluetypes.c \ +# GRuntime header files that don't get installed +gruntime_private_h_sources = +# GRuntime C sources to build the library from +gruntime_c_sources = @STRIP_BEGIN@ \ + gboxed.c \ + gbsearcharray.c \ + gclosure.c \ + genums.c \ + gobject.c \ + gparam.c \ + gparamspecs.c \ + gsignal.c \ + gtype.c \ + gtypemodule.c \ + gtypeplugin.c \ + gvalue.c \ + gvaluetypes.c \ @STRIP_END@ +# we use our own built_sources variable rules to avoid automake's +# BUILT_SOURCES oddities +# we generate frequently rebuild files piggyback on a stamp file, so sources +# depending on them only get rebuild when the built source actually changed +# content + +# built sources that get installed with the header files +gruntime_built_public_sources = @STRIP_BEGIN@ \ + gmarshal.h \ +@STRIP_END@ +# built sources that don't get installed +gruntime_built_sources = @STRIP_BEGIN@ \ + stamp-gmarshal.h \ + gmarshal.c \ + ${gruntime_built_public_sources} \ +@STRIP_END@ # non-header sources (headers should be specified in the above variables) # that don't serve as direct make target sources, i.e. they don't have # their own .lo rules and don't get publically installed -gobject_extra_sources = +gruntime_extra_sources = @STRIP_BEGIN@ \ + gmarshal.list \ + gmarshal.strings \ +@STRIP_END@ + # -# setup GObject sources and their dependancies +# setup GRuntime sources and their dependancies # -gobject_h_sources = $(gobject_private_h_sources) $(gobject_public_h_sources) # $(gobject_built_public_sources) -libgobjectinclude_HEADERS = $(gobject_public_h_sources) # $(gobject_built_public_sources) -libgobject_1_3_la_SOURCES = $(gobject_c_sources) -MAINTAINERCLEANFILES += -# $(gobject_built_public_sources) $(gobject_built_sources) +gruntime_target_headers = $(gruntime_public_h_sources) $(gruntime_built_public_sources) +gruntime_target_sources = $(gruntime_c_sources) +MAINTAINERCLEANFILES += $(gruntime_built_sources) EXTRA_HEADERS += -EXTRA_DIST += $(gobject_private_h_sources) -EXTRA_DIST += $(gobject_extra_sources) -# $(gobject_built_sources) $(gobject_built_public_sources) +EXTRA_DIST += $(gruntime_private_h_sources) $(gruntime_extra_sources) +EXTRA_DIST += $(gruntime_built_sources) + +# +# rules to generate built sources +# +# setup autogeneration dependancies +gen_sources = xgen-gmh xgen-gmc xgen-gms +CLEANFILES += $(gen_sources) +Makefile: oldest-source-stamp # oh boy, does automake SUCK! +oldest-source-stamp: $(gruntime_built_sources) +$(OBJECTS): oldest-source-stamp ${gruntime_built_public_sources} # this is our oldest file, used for implicit auto-generation deps +# initial creation of the real stamp-* files +gmarshal.h: # never add deps here + test -f "$(srcdir)/$@" || touch $(srcdir)/$@ +# normal autogeneration rules +# all autogenerated files need to be generated in the srcdir, +# so old versions get remade and are not confused with newer +# versions in the build dir. thus a development setup requires +# srcdir to be writable, passing --disable-rebuilds to +# ../configure will supress all autogeneration rules. +$(srcdir)/stamp-gmarshal.h: @REBUILD@ gmarshal.list gmarshal.h glib-genmarshal + cd $(srcdir) \ + && echo "#ifndef __G_MARSHAL_H__" > xgen-gmh \ + && echo "#define __G_MARSHAL_H__" >> xgen-gmh \ + && ./glib-genmarshal --nostdinc --prefix=g_cclosure_marshal gmarshal.list --header >> xgen-gmh \ + && echo "#endif /* __G_MARSHAL_H__ */" >> xgen-gmh \ + && (cmp -s xgen-gmh gmarshal.h || cp xgen-gmh gmarshal.h) \ + && rm -f xgen-gmh xgen-gmh~ \ + && echo timestamp > $(@F) +$(srcdir)/gmarshal.c: @REBUILD@ $(srcdir)/stamp-gmarshal.h + cd $(srcdir) \ + && ./glib-genmarshal --nostdinc --prefix=g_cclosure_marshal gmarshal.list --body >> xgen-gmc \ + && cp xgen-gmc gmarshal.c \ + && rm -f xgen-gmc xgen-gmc~ +$(srcdir)/gmarshal.strings: @REBUILD@ $(srcdir)/gmarshal.list + cd $(srcdir) \ + && grep '^[A-Z]' $(srcdir)/gmarshal.list \ + | sed -e 's/^/"g_cclosure_marshal_/' -e 's/:/__/' -e 's/,/_/g' -e 's/$$/",/' > xgen-gms \ + && cp xgen-gms gmarshal.strings \ + && rm -f xgen-gms xgen-gms~ +glib-genmarshal.o: gmarshal.strings + + +# target platform: +libgobjectinclude_HEADERS = $(gruntime_target_headers) +libgobject_1_3_la_SOURCES = $(gruntime_target_sources) # # programs to compile and install @@ -86,8 +149,8 @@ gobject_query_SOURCES = gobject-query.c glib_genmarshal_SOURCES = glib-genmarshal.c # link programs against libgobject progs_LDADD = ../libglib-1.3.la libgobject-1.3.la +glib_genmarshal_LDADD = ../libglib-1.3.la # can't have libgobject here gobject_query_LDADD = $(progs_LDADD) -glib_genmarshal_LDADD = $(progs_LDADD) # # manual pages to install @@ -123,4 +186,3 @@ dist-hook: $(BUILT_EXTRA_DIST) for f in $$files; do \ if test -f $$f; then d=.; else d=$(srcdir); fi; \ cp $$d/$$f $(distdir) || exit 1; done - diff --git a/gobject/gboxed.c b/gobject/gboxed.c index d9d00af..c3d90de 100644 --- a/gobject/gboxed.c +++ b/gobject/gboxed.c @@ -127,7 +127,7 @@ boxed_proxy_collect_value (GValue *value, key.type = value->g_type; node = g_bsearch_array_lookup (&boxed_bsa, &key); - value->data[0].v_pointer = node->copy (collect_value->v_pointer); + value->data[0].v_pointer = collect_value->v_pointer ? node->copy (collect_value->v_pointer) : NULL; *collect_type = 0; return NULL; @@ -147,7 +147,7 @@ boxed_proxy_lcopy_value (const GValue *value, key.type = value->g_type; node = g_bsearch_array_lookup (&boxed_bsa, &key); - *boxed_p = node->copy (value->data[0].v_pointer); + *boxed_p = value->data[0].v_pointer ? node->copy (value->data[0].v_pointer) : NULL; *collect_type = 0; return NULL; diff --git a/gobject/gclosure.c b/gobject/gclosure.c index d1844f7..258861d 100644 --- a/gobject/gclosure.c +++ b/gobject/gclosure.c @@ -524,8 +524,8 @@ g_type_iface_meta_marshal (GClosure *closure, } GClosure* -g_signal_type_closure_new (GType itype, - guint struct_offset) +g_signal_type_cclosure_new (GType itype, + guint struct_offset) { GClosure *closure; diff --git a/gobject/gclosure.h b/gobject/gclosure.h index 4720fda..c3ff793 100644 --- a/gobject/gclosure.h +++ b/gobject/gclosure.h @@ -32,6 +32,7 @@ extern "C" { /* --- defines --- */ #define G_CLOSURE_NEEDS_MARSHAL(closure) (((GClosure*) (closure))->marshal == NULL) #define G_CCLOSURE_SWAP_DATA(cclosure) (((GClosure*) (closure))->derivative_flag) +#define G_CALLBACK(f) ((GCallback) (f)) /* -- typedefs --- */ @@ -105,7 +106,7 @@ GClosure* g_cclosure_new (GCallback callback_func, GClosure* g_cclosure_new_swap (GCallback callback_func, gpointer user_data, GClosureNotify destroy_data); -GClosure* g_signal_type_closure_new (GType itype, +GClosure* g_signal_type_cclosure_new (GType itype, guint struct_offset); @@ -146,35 +147,14 @@ void g_closure_invoke (GClosure *closure, /* FIXME: - data_object::destroy -> closure_invalidate(); - closure_invalidate() -> disconnect(closure); - disconnect(closure) -> (unlink) closure_unref(); - closure_finalize() -> g_free (data_string); - - 1) need GObject and GType in glib - 2) need GParam - 3) need to resolve dtor cycles - 4) need GSignal move - 5) destroy on last caller ref or last data ref? - - - random remarks: - - don't mandate signals for GObject - - OTOH, don't mandate GObject for GSignal - - need marshaller repo with decent aliasing to base types - - provide marshaller collection, virtually covering anything out there - - at that point, still need GSignalCMarhsaller to g_signal_new() ? - - can we combine varargs collect mechanisms with marshaller stubs? - for out values (i.e. returntypes), that might get rid of the following - point... - - char* return signals with connections ala: - connect({ return "static data that can't work"; }), - connect({ return g_strdup ("properly duplicated string"); }) - won't work anymore. CRASH - - problems: - - accumulator needs gboolean to indicate EMISSION_STOP - - accumulator needs data + OK: data_object::destroy -> closure_invalidate(); + MIS: closure_invalidate() -> disconnect(closure); + MIS: disconnect(closure) -> (unlink) closure_unref(); + OK: closure_finalize() -> g_free (data_string); + + random remarks: + - need marshaller repo with decent aliasing to base types + - provide marshaller collection, virtually covering anything out there */ diff --git a/gobject/glib-genmarshal.1 b/gobject/glib-genmarshal.1 index d68ff6b..687b020 100644 --- a/gobject/glib-genmarshal.1 +++ b/gobject/glib-genmarshal.1 @@ -35,6 +35,10 @@ Specify marshaller prefix. The default prefix is `\fIg_cclosure_marshal\fP'. \fI--skip-source Skip source location remarks in generated comments. .TP +\fI--nostdinc +Do not use the standard GRuntime marshallers, and skip gmarshal.h include +directive in generated header files. +.TP \fI--g-fatal-warnings Make warnings fatal, that is, exit immediately once a warning occours. .TP @@ -118,6 +122,8 @@ for string types (gchar*) \fIBOXED for boxed (anonymous but reference counted) types (GBoxed*) .TP 12 +\fIPARAM +for GParamSpec or derived types (GParamSpec*) \fIPOINTER for anonymous pointer types (gpointer) .TP 12 diff --git a/gobject/glib-genmarshal.c b/gobject/glib-genmarshal.c index 0c3214a..f1b4c3b 100644 --- a/gobject/glib-genmarshal.c +++ b/gobject/glib-genmarshal.c @@ -18,7 +18,13 @@ */ #include "config.h" -#include + +/* ok, this is a bit hackish, have to provide gruntime log domain as + * we don't link against -lgruntime + */ +char *g_log_domain_gruntime = "GLib-Genmarshal"; + +#include #include #include @@ -108,11 +114,13 @@ static GScannerConfig scanner_config_template = FALSE /* symbol_2_token */, FALSE /* scope_0_fallback */, }; -static gchar *marshaller_prefix = "g_cclosure_marshal"; +static gchar *std_marshaller_prefix = "g_cclosure_marshal"; +static gchar *marshaller_prefix = "g_cclosure_user_marshal"; static GHashTable *marshallers = NULL; static gboolean gen_cheader = FALSE; static gboolean gen_cbody = FALSE; static gboolean skip_ploc = FALSE; +static gboolean std_includes = TRUE; /* --- functions --- */ @@ -142,12 +150,14 @@ complete_arg (Argument *arg, { "STRING", "POINTER", "as_pointer", "gpointer", }, { "BOXED", "POINTER", "as_pointer", "gpointer", }, { "POINTER", "POINTER", "as_pointer", "gpointer", }, + { "PARAM", "POINTER", "as_pointer", "gpointer", }, { "OBJECT", "POINTER", "as_pointer", "gpointer", }, }; static const Argument out_arguments[] = { { "STRING", "STRING", "string", "gchar*", }, { "BOXED", "BOXED", "boxed", "gpointer", }, { "POINTER", "POINTER", "pointer", "gpointer", }, + { "PARAM", "PARAM", "param", "GParamSpec*", }, { "OBJECT", "OBJECT", "object", "GObject*", }, }; const guint n_inout_arguments = sizeof (inout_arguments) / sizeof (inout_arguments[0]); @@ -201,7 +211,7 @@ pad (const gchar *string) { g_free (buffer); buffer = g_strdup_printf ("%s ", string); - g_warning ("overfull string (%lu bytes) for padspace", strlen (string)); + g_warning ("overfull string (%u bytes) for padspace", (guint) strlen (string)); return buffer; } @@ -241,17 +251,39 @@ generate_marshal (const gchar *signame, { guint ind, a; GList *node; + gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL); + gboolean have_std_marshaller = FALSE; - if (g_hash_table_lookup (marshallers, signame)) - return; + /* here we have to make sure a marshaller named _ + * exists. we might have put it out already, can revert to a standard marshaller + * provided by glib, or need to generate one. + */ + + if (g_hash_table_lookup (marshallers, tmp)) + { + /* done, marshaller already generated */ + g_free (tmp); + return; + } else { - gchar *tmp = g_strdup (signame); - + /* need to alias/generate marshaller, register name */ g_hash_table_insert (marshallers, tmp, tmp); } - - if (gen_cheader) + + /* can we revert to a standard marshaller? */ + if (std_includes) + { + tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL); + have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL; + g_free (tmp); + } + + if (gen_cheader && have_std_marshaller) + { + fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame); + } + if (gen_cheader && !have_std_marshaller) { ind = fprintf (fout, "extern void "); ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame); @@ -262,7 +294,7 @@ generate_marshal (const gchar *signame, fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind)); fprintf (fout, "%sgpointer marshal_data);\n", indent (ind)); } - if (gen_cbody) + if (gen_cbody && !have_std_marshaller) { /* cfile marhsal header */ fprintf (fout, "void\n"); @@ -352,7 +384,7 @@ generate_marshal (const gchar *signame, static void process_signature (Signature *sig) { - gchar *pname, *sname; + gchar *pname, *sname, *tmp; GList *node; /* lookup and complete info on arguments */ @@ -400,18 +432,19 @@ process_signature (Signature *sig) fprintf (fout, " (%s)", sig->ploc); fprintf (fout, " */\n"); - /* generate signature marshaller */ + /* ensure technical marshaller exists (_) */ generate_marshal (sname, sig); - /* put out marshaler alias if required */ - if (gen_cheader && !g_hash_table_lookup (marshallers, pname)) + /* put out marshaller alias for requested name if required (_) */ + tmp = g_strconcat (marshaller_prefix, "_", pname, NULL); + if (gen_cheader && !g_hash_table_lookup (marshallers, tmp)) { - gchar *tmp = g_strdup (pname); - fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname); g_hash_table_insert (marshallers, tmp, tmp); } + else + g_free (tmp); g_free (pname); g_free (sname); @@ -482,6 +515,9 @@ int main (int argc, char *argv[]) { + const gchar *gruntime_marshallers[] = { +#include "gmarshal.strings" + }; GScanner *scanner; GSList *slist, *files = NULL; gint i; @@ -502,6 +538,24 @@ main (int argc, fout = stdout; marshallers = g_hash_table_new (g_str_hash, g_str_equal); + /* add GRuntime standard marshallers */ + if (std_includes) + for (i = 0; i < sizeof (gruntime_marshallers) / sizeof (gruntime_marshallers[0]); i++) + { + gchar *tmp = g_strdup (gruntime_marshallers[i]); + + g_hash_table_insert (marshallers, tmp, tmp); + } + + /* put out initial heading */ + fprintf (fout, "\n"); + if (gen_cheader) + { + if (std_includes) + fprintf (fout, "#include\t\n\n"); + fprintf (fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n"); + } + /* process input files */ for (slist = files; slist; slist = slist->next) { @@ -579,6 +633,13 @@ main (int argc, close (fd); } + /* put out trailer */ + if (gen_cheader) + { + fprintf (fout, "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n"); + } + fprintf (fout, "\n"); + /* clean up */ g_slist_free (files); g_scanner_destroy (scanner); @@ -613,6 +674,16 @@ parse_args (gint *argc_p, skip_ploc = TRUE; argv[i] = NULL; } + else if (strcmp ("--nostdinc", argv[i]) == 0) + { + std_includes = FALSE; + argv[i] = NULL; + } + else if (strcmp ("--stdinc", argv[i]) == 0) + { + std_includes = TRUE; + argv[i] = NULL; + } else if ((strcmp ("--prefix", argv[i]) == 0) || (strncmp ("--prefix=", argv[i], 9) == 0)) { @@ -690,12 +761,13 @@ print_blurb (FILE *bout, else { fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME); - fprintf (bout, " --header generate C headers\n"); - fprintf (bout, " --body generate C code\n"); - fprintf (bout, " --prefix=string specify marshaller prefix\n"); - fprintf (bout, " --skip-source skip source location comments\n"); - fprintf (bout, " -h, --help show this help message\n"); - fprintf (bout, " -v, --version print version informations\n"); - fprintf (bout, " --g-fatal-warnings make warnings fatal (abort)\n"); + fprintf (bout, " --header generate C headers\n"); + fprintf (bout, " --body generate C code\n"); + fprintf (bout, " --prefix=string specify marshaller prefix\n"); + fprintf (bout, " --skip-source skip source location comments\n"); + fprintf (bout, " --stdinc, --nostdinc include/use GRuntime standard marshallers\n"); + fprintf (bout, " -h, --help show this help message\n"); + fprintf (bout, " -v, --version print version informations\n"); + fprintf (bout, " --g-fatal-warnings make warnings fatal (abort)\n"); } } diff --git a/gobject/gobject.c b/gobject/gobject.c index 8f94c18..f1be160 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -16,33 +16,68 @@ * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */ -#include "gobject.h" +#include "gobject.h" -#include "gvaluecollector.h" -#include "gsignal.h" -#include +#include "gvaluecollector.h" +#include "gsignal.h" +#include "gparamspecs.h" +#include "gvaluetypes.h" +#include +#define PREALLOC_CPARAMS (8) #define DEBUG_OBJECTS /* --- macros --- */ -#define PARAM_SPEC_PARAM_ID(pspec) (GPOINTER_TO_UINT (g_param_spec_get_qdata ((pspec), quark_param_id))) +#define PARAM_SPEC_PARAM_ID(pspec) (GPOINTER_TO_UINT (g_param_spec_get_qdata ((pspec), quark_property_id))) + + +/* --- signals --- */ +enum { + PROPERTIES_CHANGED, + NOTIFY, + LAST_SIGNAL +}; + + +/* --- properties --- */ +enum { + PROP_NONE, + PROP_DATA, + PROP_SIGNAL, + PROP_SWAPPED_SIGNAL, + PROP_SIGNAL_AFTER, + PROP_SWAPPED_SIGNAL_AFTER +}; + + +/* --- typedefs --- */ +typedef struct _NotifyQueue NotifyQueue; /* --- prototypes --- */ static void g_object_base_class_init (GObjectClass *class); static void g_object_base_class_finalize (GObjectClass *class); static void g_object_do_class_init (GObjectClass *class); -static void g_object_do_init (GObject *object); -static void g_object_do_queue_param_changed (GObject *object, - GParamSpec *pspec); -static void g_object_do_dispatch_param_changed (GObject *object, - GParamSpec *pspec); +static void g_object_init (GObject *object); +static GObject* g_object_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params); static void g_object_last_unref (GObject *object); -static void g_object_do_shutdown (GObject *object); -static void g_object_do_finalize (GObject *object); +static void g_object_shutdown (GObject *object); +static void g_object_finalize (GObject *object); +static void g_object_do_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec, + const gchar *trailer); +static void g_object_do_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec, + const gchar *trailer); static void g_value_object_init (GValue *value); static void g_value_object_free_value (GValue *value); static void g_value_object_copy_value (const GValue *src_value, @@ -56,13 +91,46 @@ static gchar* g_value_object_lcopy_value (const GValue *value, guint nth_value, GType *collect_type, GTypeCValue *collect_value); +static void g_object_dispatch_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs); +static void g_object_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs); +static void g_object_notify_property_changed (GObject *object, + GParamSpec *pspec); +static inline NotifyQueue* object_freeze_notifies (GObject *object); +static inline void object_queue_property (GObject *object, + GParamSpec *pspec, + NotifyQueue *nqueue); +static inline void object_thaw_notifies (GObject *object, + NotifyQueue *nqueue); +static inline void object_get_property (GObject *object, + GValue *value, + GParamSpec *pspec, + const gchar *trailer); +static inline void object_set_property (GObject *object, + GValue *value, + GParamSpec *pspec, + const gchar *trailer, + NotifyQueue *nqueue); + + +/* --- structures --- */ +struct _NotifyQueue +{ + GSList *pspecs; + guint n_pspecs; + guint freeze_count; +}; /* --- variables --- */ -static GQuark quark_param_id = 0; -static GQuark quark_param_changed_queue = 0; +static GQuark quark_notify_queue = 0; +static GQuark quark_property_id = 0; static GQuark quark_closure_array = 0; -static GHashTable *param_spec_hash_table = NULL; +static GHashTable *pspec_hash_table = NULL; +static gulong gobject_signals[LAST_SIGNAL] = { 0, }; /* --- functions --- */ @@ -118,7 +186,7 @@ g_object_type_init (void) /* sync with gtype.c */ NULL /* class_data */, sizeof (GObject), 0 /* n_preallocs */, - (GInstanceInitFunc) g_object_do_init, + (GInstanceInitFunc) g_object_init, NULL, /* value_table */ }; static const GTypeValueTable value_table = { @@ -151,10 +219,10 @@ static void g_object_base_class_init (GObjectClass *class) { /* reset instance specific fields and methods that don't get inherited */ - class->n_param_specs = 0; - class->param_specs = NULL; - class->get_param = NULL; - class->set_param = NULL; + class->n_property_specs = 0; + class->property_specs = NULL; + class->get_property = NULL; + class->set_property = NULL; } static void @@ -166,95 +234,193 @@ g_object_base_class_finalize (GObjectClass *class) _g_signals_destroy (G_OBJECT_CLASS_TYPE (class)); - for (i = 0; i < class->n_param_specs; i++) + for (i = 0; i < class->n_property_specs; i++) { - GParamSpec *pspec = class->param_specs[i]; + GParamSpec *pspec = class->property_specs[i]; - g_param_spec_hash_table_remove (param_spec_hash_table, pspec); - g_param_spec_set_qdata (pspec, quark_param_id, NULL); + g_param_spec_hash_table_remove (pspec_hash_table, pspec); + g_param_spec_set_qdata (pspec, quark_property_id, NULL); g_param_spec_unref (pspec); } - class->n_param_specs = 0; - g_free (class->param_specs); - class->param_specs = NULL; + class->n_property_specs = 0; + g_free (class->property_specs); + class->property_specs = NULL; } static void g_object_do_class_init (GObjectClass *class) { - quark_param_id = g_quark_from_static_string ("glib-object-param-id"); - quark_param_changed_queue = g_quark_from_static_string ("glib-object-param-changed-queue"); + quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); + quark_property_id = g_quark_from_static_string ("GObject-property-id"); quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); - param_spec_hash_table = g_param_spec_hash_table_new (); - - class->queue_param_changed = g_object_do_queue_param_changed; - class->dispatch_param_changed = g_object_do_dispatch_param_changed; - class->shutdown = g_object_do_shutdown; - class->finalize = g_object_do_finalize; + pspec_hash_table = g_param_spec_hash_table_new (); + + class->constructor = g_object_constructor; + class->set_property = g_object_do_set_property; + class->get_property = g_object_do_get_property; + class->shutdown = g_object_shutdown; + class->finalize = g_object_finalize; + class->dispatch_properties_changed = g_object_dispatch_properties_changed; + class->properties_changed = g_object_properties_changed; + class->notify = g_object_notify_property_changed; + + g_object_class_install_property (class, + PROP_DATA, + g_param_spec_pointer ("data", "Named Data", + "Named anonymous pointers", + G_PARAM_READABLE | G_PARAM_WRITABLE)); + g_object_class_install_property (class, + PROP_SIGNAL, + g_param_spec_ccallback ("signal", "Signal Connection", + "Signal connection consisting of a callback function " + "and a data pointer", + G_PARAM_WRITABLE)); + g_object_class_install_property (class, + PROP_SWAPPED_SIGNAL, + g_param_spec_ccallback ("swapped_signal", "Swapped Signal Connection", + "Signal connection consisting of a callback function " + "and a data pointer", + G_PARAM_WRITABLE)); + g_object_class_install_property (class, + PROP_SIGNAL_AFTER, + g_param_spec_ccallback ("signal_after", "Signal After Connection", + "Signal connection consisting of a callback function " + "and a data pointer", + G_PARAM_WRITABLE)); + g_object_class_install_property (class, + PROP_SWAPPED_SIGNAL_AFTER, + g_param_spec_ccallback ("swapped_signal_after", "Swapped Signal After Connection", + "Signal connection consisting of a callback function " + "and a data pointer", + G_PARAM_WRITABLE)); + gobject_signals[PROPERTIES_CHANGED] = + g_signal_new ("properties_changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (class), + G_STRUCT_OFFSET (GObjectClass, properties_changed)), + NULL, /* accumulator */ + g_cclosure_marshal_VOID__UINT_POINTER, + G_TYPE_NONE, + 2, G_TYPE_UINT, G_TYPE_POINTER); + gobject_signals[NOTIFY] = + g_signal_new ("notify", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS, + g_signal_type_cclosure_new (G_TYPE_FROM_CLASS (class), + G_STRUCT_OFFSET (GObjectClass, notify)), + NULL, /* accumulator */ + g_cclosure_marshal_VOID__PARAM, + G_TYPE_NONE, + 1, G_TYPE_PARAM); } void -g_object_class_install_param (GObjectClass *class, - guint param_id, - GParamSpec *pspec /* 1 ref_count taken over */) +g_object_class_install_property (GObjectClass *class, + guint property_id, + GParamSpec *pspec) { guint i; g_return_if_fail (G_IS_OBJECT_CLASS (class)); g_return_if_fail (G_IS_PARAM_SPEC (pspec)); if (pspec->flags & G_PARAM_WRITABLE) - g_return_if_fail (class->set_param != NULL); + g_return_if_fail (class->set_property != NULL); if (pspec->flags & G_PARAM_READABLE) - g_return_if_fail (class->get_param != NULL); - g_return_if_fail (param_id > 0); + g_return_if_fail (class->get_property != NULL); + g_return_if_fail (property_id > 0); g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */ - + if (pspec->flags & G_PARAM_CONSTRUCT) + g_return_if_fail ((pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + if (pspec->flags & (G_PARAM_CONSTRUCT || G_PARAM_CONSTRUCT_ONLY)) + g_return_if_fail (pspec->flags & G_PARAM_WRITABLE); + /* expensive paranoia checks ;( */ - for (i = 0; i < class->n_param_specs; i++) - if (PARAM_SPEC_PARAM_ID (class->param_specs[i]) == param_id) + for (i = 0; i < class->n_property_specs; i++) + if (PARAM_SPEC_PARAM_ID (class->property_specs[i]) == property_id) { - g_warning (G_STRLOC ": class `%s' already contains a parameter `%s' with id %u, " - "cannot install parameter `%s'", + g_warning (G_STRLOC ": class `%s' already contains a property `%s' with id %u, " + "cannot install property `%s'", G_OBJECT_CLASS_NAME (class), - class->param_specs[i]->name, - param_id, + class->property_specs[i]->name, + property_id, pspec->name); return; } - if (g_object_class_find_param_spec (class, pspec->name)) + if (g_object_class_find_property (class, pspec->name)) { - g_warning (G_STRLOC ": class `%s' already contains a parameter named `%s'", + g_warning (G_STRLOC ": class `%s' already contains a property named `%s'", G_OBJECT_CLASS_NAME (class), pspec->name); return; } - - g_param_spec_set_qdata (pspec, quark_param_id, GUINT_TO_POINTER (param_id)); - g_param_spec_hash_table_insert (param_spec_hash_table, pspec, G_OBJECT_CLASS_TYPE (class)); - i = class->n_param_specs++; - class->param_specs = g_renew (GParamSpec*, class->param_specs, class->n_param_specs); - class->param_specs[i] = pspec; + + g_param_spec_ref (pspec); + g_param_spec_sink (pspec); + g_param_spec_set_qdata (pspec, quark_property_id, GUINT_TO_POINTER (property_id)); + g_param_spec_hash_table_insert (pspec_hash_table, pspec, G_OBJECT_CLASS_TYPE (class)); + i = class->n_property_specs++; + class->property_specs = g_renew (GParamSpec*, class->property_specs, class->n_property_specs); + class->property_specs[i] = pspec; } GParamSpec* -g_object_class_find_param_spec (GObjectClass *class, - const gchar *param_name) +g_object_class_find_property (GObjectClass *class, + const gchar *property_name) { g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL); - g_return_val_if_fail (param_name != NULL, NULL); + g_return_val_if_fail (property_name != NULL, NULL); - return g_param_spec_hash_table_lookup (param_spec_hash_table, - param_name, + return g_param_spec_hash_table_lookup (pspec_hash_table, + property_name, G_OBJECT_CLASS_TYPE (class), TRUE, NULL); } static void -g_object_do_init (GObject *object) +free_notify_queue (gpointer data) +{ + NotifyQueue *nqueue = data; + + g_slist_free (nqueue->pspecs); + g_free (nqueue); +} + +static inline NotifyQueue* +object_freeze_notifies (GObject *object) +{ + NotifyQueue *nqueue; + + nqueue = g_object_get_qdata (object, quark_notify_queue); + if (!nqueue) + { + nqueue = g_new0 (NotifyQueue, 1); + g_object_set_qdata_full (object, quark_notify_queue, nqueue, free_notify_queue); + } + nqueue->freeze_count++; + + return nqueue; +} + +static inline void +object_queue_property (GObject *object, + GParamSpec *pspec, + NotifyQueue *nqueue) +{ + /* we will dedup later */ + nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec); + nqueue->n_pspecs++; +} + +static void +g_object_init (GObject *object) { object->ref_count = 1; object->qdata = NULL; + /* freeze object's notification queue, g_object_new_valist() takes care of that */ + object_freeze_notifies (object); + #ifdef DEBUG_OBJECTS if (glib_debug_objects) { @@ -267,6 +433,66 @@ g_object_do_init (GObject *object) } static void +g_object_do_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec, + const gchar *trailer) +{ + guint i = 0; + + switch (property_id) + { + gboolean swapped, after; + gpointer callback, data; + case PROP_DATA: + g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + + g_object_set_data (object, trailer + 2, g_value_get_pointer (value)); + break; + case PROP_SWAPPED_SIGNAL_AFTER: + i++; + case PROP_SIGNAL_AFTER: + i++; + case PROP_SWAPPED_SIGNAL: + i++; + case PROP_SIGNAL: + after = i > 2; + swapped = i & 1; + g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + + g_value_get_ccallback (value, &callback, &data); + g_signal_connect_data (object, trailer + 2, + callback, data, NULL, + swapped, after); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +g_object_do_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec, + const gchar *trailer) +{ + switch (property_id) + { + case PROP_DATA: + g_return_if_fail (trailer[0] == ':' && trailer[1] == ':'); + + g_value_set_pointer (value, g_object_get_data (object, trailer + 2)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void g_object_last_unref (GObject *object) { g_return_if_fail (object->ref_count > 0); @@ -279,12 +505,16 @@ g_object_last_unref (GObject *object) if (object->ref_count == 0) /* may have been re-referenced meanwhile */ { G_OBJECT_GET_CLASS (object)->finalize (object); +#ifdef DEBUG_OBJECTS + if (glib_debug_objects && debug_objects_ht) + g_assert (g_hash_table_lookup (debug_objects_ht, object) == NULL); +#endif /* DEBUG_OBJECTS */ g_type_free_instance ((GTypeInstance*) object); } } static void -g_object_do_shutdown (GObject *object) +g_object_shutdown (GObject *object) { /* this function needs to be always present for unconditional * chaining, we also might add some code here later. @@ -293,7 +523,7 @@ g_object_do_shutdown (GObject *object) } static void -g_object_do_finalize (GObject *object) +g_object_finalize (GObject *object) { g_signal_handlers_destroy (object); g_datalist_clear (&object->qdata); @@ -309,116 +539,137 @@ g_object_do_finalize (GObject *object) #endif /* DEBUG_OBJECTS */ } -gpointer -g_object_new (GType object_type, - const gchar *first_param_name, - ...) +static inline void +object_thaw_notifies (GObject *object, + NotifyQueue *nqueue) { - GObject *object; - va_list var_args; + GParamSpec **pspecs; + GSList *slist; + guint n_pspecs = 0; - g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); + nqueue->freeze_count--; + if (nqueue->freeze_count) + return; + g_return_if_fail (object->ref_count > 0); - va_start (var_args, first_param_name); - object = g_object_new_valist (object_type, first_param_name, var_args); - va_end (var_args); + pspecs = g_new (GParamSpec*, nqueue->n_pspecs); + for (slist = nqueue->pspecs; slist; slist = slist->next) + { + GParamSpec *pspec = slist->data; + gint i = 0; + + /* dedup, make pspecs in the list unique */ + redo_dedup_check: + if (pspecs[i] == pspec) + continue; + if (++i < n_pspecs) + goto redo_dedup_check; + + pspecs[n_pspecs++] = pspec; + } + g_object_set_qdata (object, quark_notify_queue, NULL); - return object; + if (n_pspecs) + G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); + + g_free (pspecs); } -gpointer -g_object_new_valist (GType object_type, - const gchar *first_param_name, - va_list var_args) +static void +g_object_dispatch_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs) { - GObject *object; - - g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); - - object = (GObject*) g_type_create_instance (object_type); - if (first_param_name) - g_object_set_valist (object, first_param_name, var_args); - - return object; + g_signal_emit (object, gobject_signals[PROPERTIES_CHANGED], 0, n_pspecs, pspecs); } static void -g_object_do_dispatch_param_changed (GObject *object, - GParamSpec *pspec) +g_object_properties_changed (GObject *object, + guint n_pspecs, + GParamSpec **pspecs) { -/* g_message ("NOTIFICATION: parameter `%s' changed on object `%s'", + guint i; + + for (i = 0; i < n_pspecs; i++) + g_signal_emit (object, gobject_signals[NOTIFY], g_quark_from_string (pspecs[i]->name), pspecs[i]); +} + +static void +g_object_notify_property_changed (GObject *object, + GParamSpec *pspec) +{ + g_message ("NOTIFICATION: %s property changed on object `%s'", pspec->name, - G_OBJECT_TYPE_NAME (object));*/ + G_OBJECT_TYPE_NAME (object)); } -static gboolean -notify_param_changed_handler (gpointer data) +void +g_object_freeze_notify (GObject *object) { - GObject *object; - GObjectClass *class; - GSList *slist; - - /* FIXME: need GDK_THREADS lock */ - - object = G_OBJECT (data); - class = G_OBJECT_GET_CLASS (object); - slist = g_datalist_id_get_data (&object->qdata, quark_param_changed_queue); - - /* a reference count is still being held */ - - for (; slist; slist = slist->next) - if (slist->data) - { - GParamSpec *pspec = slist->data; - - slist->data = NULL; - class->dispatch_param_changed (object, pspec); - } - - g_datalist_id_set_data (&object->qdata, quark_param_changed_queue, NULL); - - return FALSE; + g_return_if_fail (G_IS_OBJECT (object)); + if (!object->ref_count) + return; + + g_object_ref (object); + object_freeze_notifies (object); + g_object_unref (object); } -static void -g_object_do_queue_param_changed (GObject *object, - GParamSpec *pspec) +void +g_object_notify (GObject *object, + const gchar *property_name) { - GSList *slist, *last = NULL; - - /* if this is a recursive call on this object (i.e. pspecs are queued - * for notification, while param_changed notification is currently in - * progress), we simply add them to the queue that is currently being - * dispatched. otherwise, we later dispatch parameter changed notification - * asyncronously from an idle handler untill the queue is completely empty. - */ + GParamSpec *pspec; - slist = g_datalist_id_get_data (&object->qdata, quark_param_changed_queue); - for (; slist; last = slist, slist = last->next) - if (slist->data == pspec) - return; + g_return_if_fail (G_IS_OBJECT (object)); + g_return_if_fail (property_name != NULL); + if (!object->ref_count) + return; - if (!last) + g_object_ref (object); + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, + property_name, + G_OBJECT_TYPE (object), + TRUE, NULL); + if (!pspec) + g_warning ("%s: object class `%s' has no property named `%s'", + G_STRLOC, + G_OBJECT_TYPE_NAME (object), + property_name); + else { - g_object_ref (object); - g_idle_add_full (G_NOTIFY_PRIORITY, - notify_param_changed_handler, - object, - (GDestroyNotify) g_object_unref); - g_object_set_qdata_full (object, - quark_param_changed_queue, - g_slist_prepend (NULL, pspec), - (GDestroyNotify) g_slist_free); + NotifyQueue *nqueue = object_freeze_notifies (object); + + object_queue_property (object, pspec, nqueue); + object_thaw_notifies (object, nqueue); } + g_object_unref (object); +} + +void +g_object_thaw_notify (GObject *object) +{ + NotifyQueue *nqueue; + + g_return_if_fail (G_IS_OBJECT (object)); + if (!object->ref_count) + return; + + g_object_ref (object); + nqueue = g_object_get_qdata (object, quark_notify_queue); + if (!nqueue || !nqueue->freeze_count) + g_warning (G_STRLOC ": property-changed notification for %s(%p) is not frozen", + G_OBJECT_TYPE_NAME (object), object); else - last->next = g_slist_prepend (NULL, pspec); + object_thaw_notifies (object, nqueue); + g_object_unref (object); } static inline void -object_get_param (GObject *object, - GValue *value, - GParamSpec *pspec, - const gchar *trailer) +object_get_property (GObject *object, + GValue *value, + GParamSpec *pspec, + const gchar *trailer) { GObjectClass *class; @@ -426,14 +677,15 @@ object_get_param (GObject *object, class = g_type_class_peek (pspec->owner_type); - class->get_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer); + class->get_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer); } static inline void -object_set_param (GObject *object, - GValue *value, - GParamSpec *pspec, - const gchar *trailer) +object_set_property (GObject *object, + GValue *value, + GParamSpec *pspec, + const gchar *trailer, + NotifyQueue *nqueue) { GObjectClass *class; @@ -441,24 +693,229 @@ object_set_param (GObject *object, class = g_type_class_peek (pspec->owner_type); - class->set_param (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer); + class->set_property (object, PARAM_SPEC_PARAM_ID (pspec), value, pspec, trailer); + object_queue_property (object, pspec, nqueue); +} + +gpointer +g_object_new (GType object_type, + const gchar *first_property_name, + ...) +{ + GObject *object; + va_list var_args; + + g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); + + va_start (var_args, first_property_name); + object = g_object_new_valist (object_type, first_property_name, var_args); + va_end (var_args); + + return object; +} + +gpointer +g_object_new_valist (GType object_type, + const gchar *first_property_name, + va_list var_args) +{ + NotifyQueue *nqueue; + GObject *object; + GObjectClass *class; + const gchar *name; + GObjectConstructParam *cparams = NULL, *nparams = NULL; + guint n_cparams = 0, n_nparams = 0; + + g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL); + + /* collect parameters, sort into construction and normal ones */ + name = first_property_name; + while (name) + { + const gchar *trailer = NULL; + GValue *value; + GParamSpec *pspec; + gchar *error = NULL; + + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, + name, + object_type, + TRUE, + &trailer); + if (!pspec) + { + g_warning ("%s: object class `%s' has no property named `%s'", + G_STRLOC, + g_type_name (object_type), + name); + break; + } + if (!(pspec->flags & G_PARAM_WRITABLE)) + { + g_warning ("%s: property `%s' of object class `%s' is not writable", + G_STRLOC, + pspec->name, + g_type_name (object_type)); + break; + } + + value = g_new (GValue, 1); + value->g_type = 0; + g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + G_VALUE_COLLECT (value, var_args, &error); + if (error) + { + g_warning ("%s: %s", G_STRLOC, error); + g_free (error); + + /* we purposely leak the value here, it might not be + * in a sane state if an error condition occoured + */ + break; + } + if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) + { + if (!n_cparams || n_cparams >= PREALLOC_CPARAMS) + cparams = g_renew (GObjectConstructParam, cparams, n_cparams + 1); + cparams[n_cparams].pspec = pspec; + cparams[n_cparams].value = value; + cparams[n_cparams].trailer = trailer; + n_cparams++; + } + else + { + if (!n_nparams || n_nparams >= PREALLOC_CPARAMS) + nparams = g_renew (GObjectConstructParam, nparams, n_nparams + 1); + nparams[n_nparams].pspec = pspec; + nparams[n_nparams].value = value; + nparams[n_nparams].trailer = trailer; + n_nparams++; + } + + name = va_arg (var_args, gchar*); + } + + /* construct object from construction parameters */ + class = g_type_class_ref (object_type); + object = class->constructor (object_type, n_cparams, cparams); + g_type_class_unref (class); + + /* free construction values */ + while (n_cparams--) + { + g_value_unset (cparams[n_cparams].value); + g_free (cparams[n_cparams].value); + } + g_free (cparams); + + /* release g_object_init() notification queue freeze_count */ + nqueue = object_freeze_notifies (object); + nqueue->freeze_count--; + + /* set remaining properties */ + while (n_nparams--) + { + GValue *value = nparams[n_nparams].value; + GParamSpec *pspec = nparams[n_nparams].pspec; + const gchar *trailer = nparams[n_nparams].trailer; + + /* convert if necessary */ + if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) + { + GValue tmp_value = { 0, }; + + g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + if (!g_value_convert (value, &tmp_value) || + g_param_value_validate (pspec, &tmp_value)) + g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'", + G_STRLOC, + G_VALUE_TYPE_NAME (value), + pspec->name, + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); + else + object_set_property (object, &tmp_value, pspec, trailer, nqueue); + g_value_unset (&tmp_value); + } + else + object_set_property (object, value, pspec, trailer, nqueue); + + g_value_unset (value); + g_free (value); + } + g_free (nparams); + + /* release our own freeze count and handle notifications */ + object_thaw_notifies (object, nqueue); - class->queue_param_changed (object, pspec); + return object; +} + +static GObject* +g_object_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params) +{ + GObject *object; + + /* create object */ + object = (GObject*) g_type_create_instance (type); + + /* set construction parameters */ + if (n_construct_properties) + { + NotifyQueue *nqueue = object_freeze_notifies (object); + + /* set construct properties */ + while (n_construct_properties--) + { + GValue *value = construct_params[n_construct_properties].value; + GParamSpec *pspec = construct_params[n_construct_properties].pspec; + const gchar *trailer = construct_params[n_construct_properties].trailer; + + /* convert if necessary */ + if (!g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) + { + GValue tmp_value = { 0, }; + + g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + if (!g_value_convert (value, &tmp_value) || + g_param_value_validate (pspec, &tmp_value)) + g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'", + G_STRLOC, + G_VALUE_TYPE_NAME (value), + pspec->name, + g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); + else + object_set_property (object, &tmp_value, pspec, trailer, nqueue); + g_value_unset (&tmp_value); + } + else + object_set_property (object, value, pspec, trailer, nqueue); + } + nqueue->freeze_count--; + /* the notification queue is still frozen from g_object_init(), so + * we don't need to handle it here, g_object_new_valist() takes + * care of that + */ + } + + return object; } void g_object_set_valist (GObject *object, - const gchar *first_param_name, + const gchar *first_property_name, va_list var_args) { + NotifyQueue *nqueue; const gchar *name; g_return_if_fail (G_IS_OBJECT (object)); g_object_ref (object); + nqueue = object_freeze_notifies (object); - name = first_param_name; - + name = first_property_name; while (name) { const gchar *trailer = NULL; @@ -466,14 +923,14 @@ g_object_set_valist (GObject *object, GParamSpec *pspec; gchar *error = NULL; - pspec = g_param_spec_hash_table_lookup (param_spec_hash_table, + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, name, G_OBJECT_TYPE (object), TRUE, &trailer); if (!pspec) { - g_warning ("%s: object class `%s' has no parameter named `%s'", + g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, G_OBJECT_TYPE_NAME (object), name); @@ -481,7 +938,7 @@ g_object_set_valist (GObject *object, } if (!(pspec->flags & G_PARAM_WRITABLE)) { - g_warning ("%s: parameter `%s' of object class `%s' is not writable", + g_warning ("%s: property `%s' of object class `%s' is not writable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object)); @@ -502,19 +959,20 @@ g_object_set_valist (GObject *object, break; } - object_set_param (object, &value, pspec, trailer); + object_set_property (object, &value, pspec, trailer, nqueue); g_value_unset (&value); name = va_arg (var_args, gchar*); } - + + object_thaw_notifies (object, nqueue); g_object_unref (object); } void g_object_get_valist (GObject *object, - const gchar *first_param_name, + const gchar *first_property_name, va_list var_args) { const gchar *name; @@ -523,23 +981,23 @@ g_object_get_valist (GObject *object, g_object_ref (object); - name = first_param_name; + name = first_property_name; while (name) { const gchar *trailer = NULL; GValue value = { 0, }; GParamSpec *pspec; - gchar *error = NULL; + gchar *error; - pspec = g_param_spec_hash_table_lookup (param_spec_hash_table, + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, name, G_OBJECT_TYPE (object), TRUE, &trailer); if (!pspec) { - g_warning ("%s: object class `%s' has no parameter named `%s'", + g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, G_OBJECT_TYPE_NAME (object), name); @@ -547,7 +1005,7 @@ g_object_get_valist (GObject *object, } if (!(pspec->flags & G_PARAM_READABLE)) { - g_warning ("%s: parameter `%s' of object class `%s' is not readable", + g_warning ("%s: property `%s' of object class `%s' is not readable", G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (object)); @@ -556,7 +1014,7 @@ g_object_get_valist (GObject *object, g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - object_get_param (object, &value, pspec, trailer); + object_get_property (object, &value, pspec, trailer); G_VALUE_LCOPY (&value, var_args, &error); if (error) @@ -580,56 +1038,58 @@ g_object_get_valist (GObject *object, void g_object_set (GObject *object, - const gchar *first_param_name, + const gchar *first_property_name, ...) { va_list var_args; g_return_if_fail (G_IS_OBJECT (object)); - va_start (var_args, first_param_name); - g_object_set_valist (object, first_param_name, var_args); + va_start (var_args, first_property_name); + g_object_set_valist (object, first_property_name, var_args); va_end (var_args); } void g_object_get (GObject *object, - const gchar *first_param_name, + const gchar *first_property_name, ...) { va_list var_args; g_return_if_fail (G_IS_OBJECT (object)); - va_start (var_args, first_param_name); - g_object_get_valist (object, first_param_name, var_args); + va_start (var_args, first_property_name); + g_object_get_valist (object, first_property_name, var_args); va_end (var_args); } void -g_object_set_param (GObject *object, - const gchar *param_name, - const GValue *value) +g_object_set_property (GObject *object, + const gchar *property_name, + const GValue *value) { + NotifyQueue *nqueue; GParamSpec *pspec; const gchar *trailer; g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (param_name != NULL); + g_return_if_fail (property_name != NULL); g_return_if_fail (G_IS_VALUE (value)); g_object_ref (object); + nqueue = object_freeze_notifies (object); - pspec = g_param_spec_hash_table_lookup (param_spec_hash_table, - param_name, + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, + property_name, G_OBJECT_TYPE (object), TRUE, &trailer); if (!pspec) - g_warning ("%s: object class `%s' has no parameter named `%s'", + g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, G_OBJECT_TYPE_NAME (object), - param_name); + property_name); else { GValue tmp_value = { 0, }; @@ -639,65 +1099,66 @@ g_object_set_param (GObject *object, if (!g_value_convert (value, &tmp_value) || g_param_value_validate (pspec, &tmp_value)) - g_warning ("%s: cannot convert `%s' value to parameter `%s' value of type `%s'", + g_warning ("%s: cannot convert `%s' value to property `%s' value of type `%s'", G_STRLOC, G_VALUE_TYPE_NAME (value), pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))); else - object_set_param (object, &tmp_value, pspec, trailer); + object_set_property (object, &tmp_value, pspec, trailer, nqueue); g_value_unset (&tmp_value); } + object_thaw_notifies (object, nqueue); g_object_unref (object); } void -g_object_get_param (GObject *object, - const gchar *param_name, - GValue *value) +g_object_get_property (GObject *object, + const gchar *property_name, + GValue *value) { GParamSpec *pspec; const gchar *trailer; g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (param_name != NULL); + g_return_if_fail (property_name != NULL); g_return_if_fail (G_IS_VALUE (value)); g_object_ref (object); - pspec = g_param_spec_hash_table_lookup (param_spec_hash_table, - param_name, + pspec = g_param_spec_hash_table_lookup (pspec_hash_table, + property_name, G_OBJECT_TYPE (object), TRUE, &trailer); if (!pspec) - g_warning ("%s: object class `%s' has no parameter named `%s'", + g_warning ("%s: object class `%s' has no property named `%s'", G_STRLOC, G_OBJECT_TYPE_NAME (object), - param_name); + property_name); else { GValue tmp_value = { 0, }; /* provide a copy to work from and later convert if necessary, so - * _get_param() implementations need *not* care about freeing values - * that might be already set in the parameter to get. + * _get_property() implementations need *not* care about freeing values + * that might be already set in the property to get. * (though, at this point, GValue should exclusively be modified * through the accessor functions anyways) */ g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); if (!g_value_types_exchangable (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) - g_warning ("%s: can't retrive parameter `%s' value of type `%s' as value of type `%s'", + g_warning ("%s: can't retrive property `%s' value of type `%s' as value of type `%s'", G_STRLOC, pspec->name, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), G_VALUE_TYPE_NAME (value)); else { - object_get_param (object, &tmp_value, pspec, trailer); + object_get_property (object, &tmp_value, pspec, trailer); g_value_convert (&tmp_value, value); /* g_value_validate (value, pspec); */ } @@ -708,28 +1169,6 @@ g_object_get_param (GObject *object, g_object_unref (object); } -void -g_object_queue_param_changed (GObject *object, - const gchar *param_name) -{ - GParamSpec *pspec; - - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (param_name != NULL); - - pspec = g_param_spec_hash_table_lookup (param_spec_hash_table, - param_name, - G_OBJECT_TYPE (object), - TRUE, NULL); - if (!pspec) - g_warning ("%s: object class `%s' has no parameter named `%s'", - G_STRLOC, - G_OBJECT_TYPE_NAME (object), - param_name); - else - G_OBJECT_GET_CLASS (object)->queue_param_changed (object, pspec); -} - GObject* g_object_ref (GObject *object) { @@ -799,11 +1238,14 @@ gpointer g_object_get_data (GObject *object, const gchar *key) { + GQuark quark; + g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (key != NULL, NULL); - - return g_object_get_qdata (object, - g_quark_try_string (key)); + + quark = g_quark_try_string (key); + + return quark ? g_datalist_id_get_data (&object->qdata, quark) : NULL; } void @@ -814,9 +1256,7 @@ g_object_set_data (GObject *object, g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (key != NULL); - g_object_set_qdata (object, - g_quark_from_string (key), - data); + g_datalist_id_set_data (&object->qdata, g_quark_from_string (key), data); } void @@ -828,21 +1268,21 @@ g_object_set_data_full (GObject *object, g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (key != NULL); - g_object_set_qdata_full (object, - g_quark_from_string (key), - data, - destroy); + g_datalist_id_set_data_full (&object->qdata, g_quark_from_string (key), data, data ? destroy : NULL); } gpointer g_object_steal_data (GObject *object, const gchar *key) { + GQuark quark; + g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (key != NULL, NULL); - return g_object_steal_qdata (object, - g_quark_try_string (key)); + quark = g_quark_try_string (key); + + return quark ? g_datalist_id_remove_no_notify (&object->qdata, quark) : NULL; } static void @@ -927,14 +1367,21 @@ g_value_set_object (GValue *value, GObject *v_object) { g_return_if_fail (G_IS_VALUE_OBJECT (value)); - if (v_object) - g_return_if_fail (G_IS_OBJECT (v_object)); if (value->data[0].v_pointer) - g_object_unref (value->data[0].v_pointer); - value->data[0].v_pointer = v_object; - if (value->data[0].v_pointer) - g_object_ref (value->data[0].v_pointer); + { + g_object_unref (value->data[0].v_pointer); + value->data[0].v_pointer = NULL; + } + + if (v_object) + { + g_return_if_fail (G_IS_OBJECT (v_object)); + g_return_if_fail (g_type_is_a (G_OBJECT_TYPE (v_object), G_VALUE_TYPE (value))); + + value->data[0].v_pointer = v_object; + g_object_ref (value->data[0].v_pointer); + } } GObject* @@ -953,6 +1400,32 @@ g_value_dup_object (const GValue *value) return value->data[0].v_pointer ? g_object_ref (value->data[0].v_pointer) : NULL; } +guint +g_signal_connect_object (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer gobject, + gboolean swapped, + gboolean after) +{ + g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); + g_return_val_if_fail (detailed_signal != NULL, 0); + g_return_val_if_fail (c_handler != NULL, 0); + + if (gobject) + { + GClosure *closure; + + g_return_val_if_fail (G_IS_OBJECT (gobject), 0); + + closure = (swapped ? g_cclosure_new_object_swap : g_cclosure_new_object) (c_handler, gobject); + + return g_signal_connect_closure (instance, detailed_signal, closure, after); + } + else + return g_signal_connect_data (instance, detailed_signal, c_handler, NULL, NULL, swapped, after); +} + typedef struct { GObject *object; guint n_closures; diff --git a/gobject/gobject.h b/gobject/gobject.h index 7c31d6a..4625830 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -8,7 +8,7 @@ * * 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 + * 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 @@ -19,10 +19,10 @@ #ifndef __G_OBJECT_H__ #define __G_OBJECT_H__ -#include -#include -#include -#include +#include +#include +#include +#include #ifdef __cplusplus @@ -31,161 +31,177 @@ extern "C" { /* --- type macros --- */ -#define G_TYPE_IS_OBJECT(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT) -#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject)) -#define G_OBJECT_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass)) -#define G_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_OBJECT)) +#define G_TYPE_IS_OBJECT(type) (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT) +#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject)) +#define G_OBJECT_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass)) +#define G_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), G_TYPE_OBJECT)) #define G_IS_OBJECT_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_OBJECT)) #define G_OBJECT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), G_TYPE_OBJECT, GObjectClass)) -#define G_OBJECT_TYPE(object) (G_TYPE_FROM_INSTANCE (object)) +#define G_OBJECT_TYPE(object) (G_TYPE_FROM_INSTANCE (object)) #define G_OBJECT_TYPE_NAME(object) (g_type_name (G_OBJECT_TYPE (object))) #define G_OBJECT_CLASS_TYPE(class) (G_TYPE_FROM_CLASS (class)) #define G_OBJECT_CLASS_NAME(class) (g_type_name (G_OBJECT_CLASS_TYPE (class))) #define G_IS_VALUE_OBJECT(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_OBJECT)) -#define G_NOTIFY_PRIORITY (G_PRIORITY_HIGH_IDLE + 20) - /* --- typedefs & structures --- */ -typedef struct _GObject GObject; -typedef struct _GObjectClass GObjectClass; -typedef struct _GObjectConstructParam GObjectConstructParam; -typedef void (*GObjectGetParamFunc) (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer); -typedef void (*GObjectSetParamFunc) (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec, - const gchar *trailer); -typedef void (*GObjectFinalizeFunc) (GObject *object); -struct _GObject +typedef struct _GObject GObject; +typedef struct _GObjectClass GObjectClass; +typedef struct _GObjectConstructParam GObjectConstructParam; +typedef void (*GObjectGetPropertyFunc) (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec, + const gchar *trailer); +typedef void (*GObjectSetPropertyFunc) (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec, + const gchar *trailer); +typedef void (*GObjectFinalizeFunc) (GObject *object); +struct _GObject { GTypeInstance g_type_instance; /*< private >*/ - guint ref_count; - GData *qdata; + guint ref_count; + GData *qdata; }; -struct _GObjectClass +struct _GObjectClass { GTypeClass g_type_class; - guint n_param_specs; - GParamSpec **param_specs; - - GObject* (*constructor) (GType type, // FIXME!!! - guint n_construct_params, - GObjectConstructParam *construct_params); - void (*get_param) (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec, - const gchar *trailer); - void (*set_param) (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec, - const gchar *trailer); - void (*queue_param_changed) (GObject *object, - GParamSpec *pspec); - void (*dispatch_param_changed) (GObject *object, + /* private, these fields might vanish */ + guint n_property_specs; + GParamSpec **property_specs; + + /* public overridable methods */ + GObject* (*constructor) (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_params); + void (*get_property) (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec, + const gchar *trailer); + void (*set_property) (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec, + const gchar *trailer); + void (*shutdown) (GObject *object); + void (*finalize) (GObject *object); + + /*< private >*/ + void (*dispatch_properties_changed) (GObject *object, + guint n_pspecs, + GParamSpec **pspecs); + + /* signals */ + void (*properties_changed) (GObject *object, + guint n_pspecs, + GParamSpec **pspecs); + void (*notify) (GObject *object, GParamSpec *pspec); - void (*shutdown) (GObject *object); - void (*finalize) (GObject *object); }; struct _GObjectConstructParam { - GParamSpec *pspec; - GValue *value; - gchar *trailer; + GParamSpec *pspec; + GValue *value; + const gchar *trailer; }; /* --- prototypes --- */ -void g_object_class_install_param (GObjectClass *oclass, - guint param_id, - GParamSpec *pspec /* +1 ref */); -GParamSpec* g_object_class_find_param_spec (GObjectClass *oclass, - const gchar *param_name); -gpointer g_object_new (GType object_type, - const gchar *first_param_name, - ...); -gpointer g_object_new_valist (GType object_type, - const gchar *first_param_name, - va_list var_args); -void g_object_set (GObject *object, - const gchar *first_param_name, - ...); -void g_object_get (GObject *object, - const gchar *first_param_name, - ...); -void g_object_set_valist (GObject *object, - const gchar *first_param_name, - va_list var_args); -void g_object_get_valist (GObject *object, - const gchar *first_param_name, - va_list var_args); -void g_object_set_param (GObject *object, - const gchar *param_name, - const GValue *value); -void g_object_get_param (GObject *object, - const gchar *param_name, - GValue *value); -void g_object_queue_param_changed (GObject *object, - const gchar *param_name); -GObject* g_object_ref (GObject *object); -void g_object_unref (GObject *object); -gpointer g_object_get_qdata (GObject *object, - GQuark quark); -void g_object_set_qdata (GObject *object, - GQuark quark, - gpointer data); -void g_object_set_qdata_full (GObject *object, - GQuark quark, - gpointer data, - GDestroyNotify destroy); -gpointer g_object_steal_qdata (GObject *object, - GQuark quark); -gpointer g_object_get_data (GObject *object, - const gchar *key); -void g_object_set_data (GObject *object, - const gchar *key, - gpointer data); -void g_object_set_data_full (GObject *object, - const gchar *key, - gpointer data, - GDestroyNotify destroy); -gpointer g_object_steal_data (GObject *object, - const gchar *key); -void g_object_watch_closure (GObject *object, - GClosure *closure); -GClosure* g_cclosure_new_object (GCallback callback_func, - gpointer object); -GClosure* g_cclosure_new_object_swap (GCallback callback_func, - gpointer object); -GClosure* g_closure_new_object (guint sizeof_closure, - GObject *object); -void g_value_set_object (GValue *value, - GObject *v_object); -GObject* g_value_get_object (const GValue *value); -GObject* g_value_dup_object (const GValue *value); +void g_object_class_install_property (GObjectClass *oclass, + guint property_id, + GParamSpec *pspec); +GParamSpec* g_object_class_find_property (GObjectClass *oclass, + const gchar *property_name); +gpointer g_object_new (GType object_type, + const gchar *first_property_name, + ...); +gpointer g_object_new_valist (GType object_type, + const gchar *first_property_name, + va_list var_args); +void g_object_set (GObject *object, + const gchar *first_property_name, + ...); +void g_object_get (GObject *object, + const gchar *first_property_name, + ...); +void g_object_set_valist (GObject *object, + const gchar *first_property_name, + va_list var_args); +void g_object_get_valist (GObject *object, + const gchar *first_property_name, + va_list var_args); +void g_object_set_property (GObject *object, + const gchar *property_name, + const GValue *value); +void g_object_get_property (GObject *object, + const gchar *property_name, + GValue *value); +void g_object_freeze_notify (GObject *object); +void g_object_notify (GObject *object, + const gchar *property_name); +void g_object_thaw_notify (GObject *object); +GObject* g_object_ref (GObject *object); +void g_object_unref (GObject *object); +gpointer g_object_get_qdata (GObject *object, + GQuark quark); +void g_object_set_qdata (GObject *object, + GQuark quark, + gpointer data); +void g_object_set_qdata_full (GObject *object, + GQuark quark, + gpointer data, + GDestroyNotify destroy); +gpointer g_object_steal_qdata (GObject *object, + GQuark quark); +gpointer g_object_get_data (GObject *object, + const gchar *key); +void g_object_set_data (GObject *object, + const gchar *key, + gpointer data); +void g_object_set_data_full (GObject *object, + const gchar *key, + gpointer data, + GDestroyNotify destroy); +gpointer g_object_steal_data (GObject *object, + const gchar *key); +void g_object_watch_closure (GObject *object, + GClosure *closure); +GClosure* g_cclosure_new_object (GCallback callback_func, + gpointer object); +GClosure* g_cclosure_new_object_swap (GCallback callback_func, + gpointer object); +GClosure* g_closure_new_object (guint sizeof_closure, + GObject *object); +void g_value_set_object (GValue *value, + GObject *v_object); +GObject* g_value_get_object (const GValue *value); +GObject* g_value_dup_object (const GValue *value); +guint g_signal_connect_object (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer gobject, + gboolean swapped, + gboolean after); /* --- implementation macros --- */ -#define G_WARN_INVALID_PARAM_ID(object, param_id, pspec) \ +#define G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec) \ G_STMT_START { \ GObject *_object = (GObject*) (object); \ GParamSpec *_pspec = (GParamSpec*) (pspec); \ - guint _param_id = (param_id); \ - g_warning ("%s: invalid parameter id %u for \"%s\" of type `%s' in `%s'", \ - G_STRLOC, \ - _param_id, \ - _pspec->name, \ - g_type_name (G_PARAM_SPEC_TYPE (_pspec)), \ - G_OBJECT_TYPE_NAME (_object)); \ + guint _property_id = (property_id); \ + g_warning ("%s: invalid property id %u for \"%s\" of type `%s' in `%s'", \ + G_STRLOC, \ + _property_id, \ + _pspec->name, \ + g_type_name (G_PARAM_SPEC_TYPE (_pspec)), \ + G_OBJECT_TYPE_NAME (_object)); \ } G_STMT_END diff --git a/gobject/gparam.c b/gobject/gparam.c index fd93698..fdb1508 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -19,12 +19,14 @@ #include "gparam.h" +#include "gvaluecollector.h" #include /* --- defines --- */ #define G_PARAM_SPEC_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_PARAM, GParamSpecClass)) +#define PSPEC_APPLIES_TO_VALUE(pspec, value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_PARAM_SPEC_VALUE_TYPE (pspec))) /* --- prototypes --- */ @@ -34,6 +36,23 @@ static void g_param_spec_class_init (GParamSpecClass *class, gpointer class_data); static void g_param_spec_init (GParamSpec *pspec); static void g_param_spec_finalize (GParamSpec *pspec); +static void value_param_init (GValue *value); +static void value_param_free_value (GValue *value); +static void value_param_copy_value (const GValue *src_value, + GValue *dest_value); +static gpointer value_param_peek_pointer (const GValue *value); +static gchar* value_param_collect_value (GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value); +static gchar* value_param_lcopy_value (const GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value); + + +/* --- variables --- */ +static GQuark quark_floating = 0; /* --- functions --- */ @@ -46,6 +65,16 @@ g_param_type_init (void) /* sync with gtype.c */ G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE), }; + static const GTypeValueTable param_value_table = { + value_param_init, /* value_init */ + value_param_free_value, /* value_free */ + value_param_copy_value, /* value_copy */ + value_param_peek_pointer, /* value_peek_pointer */ + G_VALUE_COLLECT_POINTER, /* collect_type */ + value_param_collect_value, /* collect_value */ + G_VALUE_COLLECT_POINTER, /* lcopy_type */ + value_param_lcopy_value, /* lcopy_value */ + }; static const GTypeInfo param_spec_info = { sizeof (GParamSpecClass), @@ -59,7 +88,7 @@ g_param_type_init (void) /* sync with gtype.c */ 0, /* n_preallocs */ (GInstanceInitFunc) g_param_spec_init, - NULL, /* value_table */ + ¶m_value_table, }; GType type; @@ -81,6 +110,8 @@ static void g_param_spec_class_init (GParamSpecClass *class, gpointer class_data) { + quark_floating = g_quark_from_static_string ("GParamSpec-floating"); + class->value_type = G_TYPE_NONE; class->finalize = g_param_spec_finalize; class->value_set_default = NULL; @@ -98,6 +129,7 @@ g_param_spec_init (GParamSpec *pspec) pspec->owner_type = 0; pspec->qdata = NULL; pspec->ref_count = 1; + g_datalist_id_set_data (&pspec->qdata, quark_floating, GUINT_TO_POINTER (TRUE)); } static void @@ -129,11 +161,28 @@ g_param_spec_unref (GParamSpec *pspec) g_return_if_fail (G_IS_PARAM_SPEC (pspec)); g_return_if_fail (pspec->ref_count > 0); + /* sync with _sink */ pspec->ref_count -= 1; if (pspec->ref_count == 0) G_PARAM_SPEC_GET_CLASS (pspec)->finalize (pspec); } +void +g_param_spec_sink (GParamSpec *pspec) +{ + g_return_if_fail (G_IS_PARAM_SPEC (pspec)); + g_return_if_fail (pspec->ref_count > 0); + + if (g_datalist_id_remove_no_notify (&pspec->qdata, quark_floating)) + { + /* sync with _unref */ + if (pspec->ref_count > 1) + pspec->ref_count -= 1; + else + g_param_spec_unref (pspec); + } +} + gpointer g_param_spec_internal (GType param_type, const gchar *name, @@ -204,7 +253,7 @@ g_param_value_set_default (GParamSpec *pspec, { g_return_if_fail (G_IS_PARAM_SPEC (pspec)); g_return_if_fail (G_IS_VALUE (value)); - g_return_if_fail (G_IS_PARAM_VALUE (pspec, value)); + g_return_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value)); g_value_reset (value); G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, value); @@ -219,7 +268,7 @@ g_param_value_defaults (GParamSpec *pspec, g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); g_return_val_if_fail (G_IS_VALUE (value), FALSE); - g_return_val_if_fail (G_IS_PARAM_VALUE (pspec, value), FALSE); + g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); g_value_init (&dflt_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); G_PARAM_SPEC_GET_CLASS (pspec)->value_set_default (pspec, &dflt_value); @@ -235,7 +284,7 @@ g_param_value_validate (GParamSpec *pspec, { g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), FALSE); g_return_val_if_fail (G_IS_VALUE (value), FALSE); - g_return_val_if_fail (G_IS_PARAM_VALUE (pspec, value), FALSE); + g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value), FALSE); if (G_PARAM_SPEC_GET_CLASS (pspec)->value_validate) { @@ -265,14 +314,90 @@ g_param_values_cmp (GParamSpec *pspec, g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), 0); g_return_val_if_fail (G_IS_VALUE (value1), 0); g_return_val_if_fail (G_IS_VALUE (value2), 0); - g_return_val_if_fail (G_IS_PARAM_VALUE (pspec, value1), 0); - g_return_val_if_fail (G_IS_PARAM_VALUE (pspec, value2), 0); + g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value1), 0); + g_return_val_if_fail (PSPEC_APPLIES_TO_VALUE (pspec, value2), 0); cmp = G_PARAM_SPEC_GET_CLASS (pspec)->values_cmp (pspec, value1, value2); return CLAMP (cmp, -1, 1); } +static void +value_param_init (GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_param_free_value (GValue *value) +{ + if (value->data[0].v_pointer) + g_param_spec_unref (value->data[0].v_pointer); +} + +static void +value_param_copy_value (const GValue *src_value, + GValue *dest_value) +{ + dest_value->data[0].v_pointer = (src_value->data[0].v_pointer + ? g_param_spec_ref (src_value->data[0].v_pointer) + : NULL); +} + +static gpointer +value_param_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +static gchar* +value_param_collect_value (GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value) +{ + if (collect_value->v_pointer) + { + GParamSpec *param = collect_value->v_pointer; + + if (param->g_type_instance.g_class == NULL) + return g_strconcat ("invalid unclassed param spec pointer for value type `", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + else if (!g_type_is_a (G_PARAM_SPEC_TYPE (param), G_VALUE_TYPE (value))) + return g_strconcat ("invalid param spec type `", + G_PARAM_SPEC_TYPE_NAME (param), + "' for value type `", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + value->data[0].v_pointer = g_param_spec_ref (param); + } + else + value->data[0].v_pointer = NULL; + + *collect_type = 0; + return NULL; +} + +static gchar* +value_param_lcopy_value (const GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value) +{ + GParamSpec **param_p = collect_value->v_pointer; + + if (!param_p) + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + + *param_p = value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL; + + *collect_type = 0; + return NULL; +} + static guint param_spec_hash (gconstpointer key_spec) { @@ -468,3 +593,34 @@ g_param_type_register_static (const gchar *name, return g_type_register_static (G_TYPE_PARAM, name, &info, 0); } + +void +g_value_set_param (GValue *value, + GParamSpec *param) +{ + g_return_if_fail (G_IS_VALUE_PARAM (value)); + if (param) + g_return_if_fail (G_IS_PARAM_SPEC (param)); + + if (value->data[0].v_pointer) + g_param_spec_unref (value->data[0].v_pointer); + value->data[0].v_pointer = param; + if (value->data[0].v_pointer) + g_param_spec_ref (value->data[0].v_pointer); +} + +GParamSpec* +g_value_get_param (const GValue *value) +{ + g_return_val_if_fail (G_IS_VALUE_PARAM (value), NULL); + + return value->data[0].v_pointer; +} + +GParamSpec* +g_value_dup_param (const GValue *value) +{ + g_return_val_if_fail (G_IS_VALUE_PARAM (value), NULL); + + return value->data[0].v_pointer ? g_param_spec_ref (value->data[0].v_pointer) : NULL; +} diff --git a/gobject/gparam.h b/gobject/gparam.h index 8b1f3f1..ec33fbc 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -37,24 +37,40 @@ extern "C" { #define G_PARAM_SPEC(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM, GParamSpec)) #define G_IS_PARAM_SPEC(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM)) #define G_PARAM_SPEC_GET_CLASS(pspec) (G_TYPE_INSTANCE_GET_CLASS ((pspec), G_TYPE_PARAM, GParamSpecClass)) -#define G_IS_PARAM_VALUE(pspec, value) (g_type_is_a (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (pspec))) /* FIXME */ #define G_PARAM_SPEC_VALUE_TYPE(pspec) (G_PARAM_SPEC_GET_CLASS (pspec)->value_type) - +#define G_IS_VALUE_PARAM(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_PARAM)) + /* --- flags --- */ typedef enum { G_PARAM_READABLE = 1 << 0, G_PARAM_WRITABLE = 1 << 1, - G_PARAM_MASK = 0x000f, + G_PARAM_CONSTRUCT = 1 << 2, + G_PARAM_CONSTRUCT_ONLY = 1 << 3, +#define G_PARAM_MASK (0x000f) /* bits in the range 0xfff0 are reserved for 3rd party usage */ - G_PARAM_USER_MASK = 0xfff0 +#define G_PARAM_USER_MASK (0xfff0) } GParamFlags; /* --- typedefs & structures --- */ -typedef struct _GParamSpecClass GParamSpecClass; typedef struct _GParamSpec GParamSpec; +typedef struct _GParamSpecClass GParamSpecClass; +struct _GParamSpec +{ + GTypeInstance g_type_instance; + + gchar *name; + gchar *nick; + gchar *blurb; + GParamFlags flags; + + /*< private >*/ + GType owner_type; + GData *qdata; + guint ref_count; +}; struct _GParamSpecClass { GTypeClass g_type_class; @@ -72,25 +88,12 @@ struct _GParamSpecClass const GValue *value1, const GValue *value2); }; -struct _GParamSpec -{ - GTypeInstance g_instance; - - gchar *name; - gchar *nick; - gchar *blurb; - GParamFlags flags; - - /*< private >*/ - GType owner_type; - GData *qdata; - guint ref_count; -}; /* --- prototypes --- */ GParamSpec* g_param_spec_ref (GParamSpec *pspec); void g_param_spec_unref (GParamSpec *pspec); +void g_param_spec_sink (GParamSpec *pspec); gpointer g_param_spec_get_qdata (GParamSpec *pspec, GQuark quark); void g_param_spec_set_qdata (GParamSpec *pspec, @@ -111,6 +114,10 @@ gboolean g_param_value_validate (GParamSpec *pspec, gint g_param_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2); +void g_value_set_param (GValue *value, + GParamSpec *param); +GParamSpec* g_value_get_param (const GValue *value); +GParamSpec* g_value_dup_param (const GValue *value); /* --- convenience functions --- */ diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c index 10b8ab3..64b63f0 100644 --- a/gobject/gparamspecs.c +++ b/gobject/gparamspecs.c @@ -541,6 +541,103 @@ param_string_values_cmp (GParamSpec *pspec, } static void +param_spec_param_init (GParamSpec *pspec) +{ + GParamSpecParam *spec = G_PARAM_SPEC_PARAM (pspec); + + spec->param_type = G_TYPE_PARAM; +} + +static void +param_param_set_default (GParamSpec *pspec, + GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static gboolean +param_param_validate (GParamSpec *pspec, + GValue *value) +{ + GParamSpecParam *spec = G_PARAM_SPEC_PARAM (pspec); + GParamSpec *param = value->data[0].v_pointer; + guint changed = 0; + + if (param && !g_type_is_a (G_PARAM_SPEC_TYPE (param), spec->param_type)) + { + g_param_spec_unref (param); + value->data[0].v_pointer = NULL; + changed++; + } + + return changed; +} + +static void +param_spec_pointer_init (GParamSpec *pspec) +{ + /* GParamSpecPointer *spec = G_PARAM_SPEC_POINTER (pspec); */ +} + +static void +param_pointer_set_default (GParamSpec *pspec, + GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static gboolean +param_pointer_validate (GParamSpec *pspec, + GValue *value) +{ + /* GParamSpecPointer *spec = G_PARAM_SPEC_POINTER (pspec); */ + guint changed = 0; + + return changed; +} + +static gint +param_pointer_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) +{ + return value1->data[0].v_pointer != value2->data[0].v_pointer; +} + +static void +param_spec_ccallback_init (GParamSpec *pspec) +{ + /* GParamSpecCCallback *spec = G_PARAM_SPEC_CCALLBACK (pspec); */ +} + +static void +param_ccallback_set_default (GParamSpec *pspec, + GValue *value) +{ + value->data[0].v_pointer = NULL; + value->data[1].v_pointer = NULL; +} + +static gboolean +param_ccallback_validate (GParamSpec *pspec, + GValue *value) +{ + /* GParamSpecCCallback *spec = G_PARAM_SPEC_CCALLBACK (pspec); */ + guint changed = 0; + + return changed; +} + +static gint +param_ccallback_values_cmp (GParamSpec *pspec, + const GValue *value1, + const GValue *value2) +{ + return (value1->data[0].v_pointer != value2->data[0].v_pointer || + value1->data[1].v_pointer != value2->data[1].v_pointer); +} + +static void param_spec_object_init (GParamSpec *pspec) { GParamSpecObject *ospec = G_PARAM_SPEC_OBJECT (pspec); @@ -919,6 +1016,57 @@ g_param_spec_types_init (void) /* sync with gtype.c */ g_assert (type == G_TYPE_PARAM_STRING); } + /* G_TYPE_PARAM_PARAM + */ + { + static const GParamSpecTypeInfo pspec_info = { + sizeof (GParamSpecParam), /* instance_size */ + 16, /* n_preallocs */ + param_spec_param_init, /* instance_init */ + G_TYPE_PARAM, /* value_type */ + NULL, /* finalize */ + param_param_set_default, /* value_set_default */ + param_param_validate, /* value_validate */ + param_pointer_values_cmp, /* values_cmp */ + }; + type = g_param_type_register_static ("GParamParam", &pspec_info); + g_assert (type == G_TYPE_PARAM_PARAM); + } + + /* G_TYPE_PARAM_POINTER + */ + { + static const GParamSpecTypeInfo pspec_info = { + sizeof (GParamSpecPointer), /* instance_size */ + 0, /* n_preallocs */ + param_spec_pointer_init, /* instance_init */ + G_TYPE_POINTER, /* value_type */ + NULL, /* finalize */ + param_pointer_set_default, /* value_set_default */ + param_pointer_validate, /* value_validate */ + param_pointer_values_cmp, /* values_cmp */ + }; + type = g_param_type_register_static ("GParamPointer", &pspec_info); + g_assert (type == G_TYPE_PARAM_POINTER); + } + + /* G_TYPE_PARAM_CCALLBACK + */ + { + static const GParamSpecTypeInfo pspec_info = { + sizeof (GParamSpecCCallback), /* instance_size */ + 0, /* n_preallocs */ + param_spec_ccallback_init, /* instance_init */ + G_TYPE_CCALLBACK, /* value_type */ + NULL, /* finalize */ + param_ccallback_set_default, /* value_set_default */ + param_ccallback_validate, /* value_validate */ + param_ccallback_values_cmp, /* values_cmp */ + }; + type = g_param_type_register_static ("GParamCCallback", &pspec_info); + g_assert (type == G_TYPE_PARAM_CCALLBACK); + } + /* G_TYPE_PARAM_OBJECT */ { @@ -1281,6 +1429,59 @@ g_param_spec_string_c (const gchar *name, } GParamSpec* +g_param_spec_param (const gchar *name, + const gchar *nick, + const gchar *blurb, + GType param_type, + GParamFlags flags) +{ + GParamSpecParam *pspec; + + g_return_val_if_fail (G_TYPE_IS_PARAM (param_type), NULL); + + pspec = g_param_spec_internal (G_TYPE_PARAM_PARAM, + name, + nick, + blurb, + flags); + pspec->param_type = param_type; + + return G_PARAM_SPEC (pspec); +} + +GParamSpec* +g_param_spec_pointer (const gchar *name, + const gchar *nick, + const gchar *blurb, + GParamFlags flags) +{ + GParamSpecPointer *pspec; + + pspec = g_param_spec_internal (G_TYPE_PARAM_POINTER, + name, + nick, + blurb, + flags); + return G_PARAM_SPEC (pspec); +} + +GParamSpec* +g_param_spec_ccallback (const gchar *name, + const gchar *nick, + const gchar *blurb, + GParamFlags flags) +{ + GParamSpecCCallback *cspec; + + cspec = g_param_spec_internal (G_TYPE_PARAM_CCALLBACK, + name, + nick, + blurb, + flags); + return G_PARAM_SPEC (cspec); +} + +GParamSpec* g_param_spec_object (const gchar *name, const gchar *nick, const gchar *blurb, diff --git a/gobject/gparamspecs.h b/gobject/gparamspecs.h index 01219d0..5fb0b00 100644 --- a/gobject/gparamspecs.h +++ b/gobject/gparamspecs.h @@ -33,48 +33,57 @@ extern "C" { /* --- type macros --- */ -#define G_IS_PARAM_SPEC_CHAR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_CHAR)) -#define G_PARAM_SPEC_CHAR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_CHAR, GParamSpecChar)) -#define G_IS_PARAM_SPEC_UCHAR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UCHAR)) -#define G_PARAM_SPEC_UCHAR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UCHAR, GParamSpecUChar)) -#define G_IS_PARAM_SPEC_BOOLEAN(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_BOOLEAN)) -#define G_PARAM_SPEC_BOOLEAN(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_BOOLEAN, GParamSpecBoolean)) -#define G_IS_PARAM_SPEC_INT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_INT)) -#define G_PARAM_SPEC_INT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_INT, GParamSpecInt)) -#define G_IS_PARAM_SPEC_UINT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UINT)) -#define G_PARAM_SPEC_UINT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UINT, GParamSpecUInt)) -#define G_IS_PARAM_SPEC_LONG(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_LONG)) -#define G_PARAM_SPEC_LONG(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_LONG, GParamSpecLong)) -#define G_IS_PARAM_SPEC_ULONG(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ULONG)) -#define G_PARAM_SPEC_ULONG(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ULONG, GParamSpecULong)) -#define G_IS_PARAM_SPEC_ENUM(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ENUM)) -#define G_PARAM_SPEC_ENUM(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ENUM, GParamSpecEnum)) -#define G_IS_PARAM_SPEC_FLAGS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLAGS)) -#define G_PARAM_SPEC_FLAGS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLAGS, GParamSpecFlags)) -#define G_IS_PARAM_SPEC_FLOAT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLOAT)) -#define G_PARAM_SPEC_FLOAT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLOAT, GParamSpecFloat)) -#define G_IS_PARAM_SPEC_DOUBLE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_DOUBLE)) -#define G_PARAM_SPEC_DOUBLE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_DOUBLE, GParamSpecDouble)) -#define G_IS_PARAM_SPEC_STRING(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_STRING)) -#define G_PARAM_SPEC_STRING(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_STRING, GParamSpecString)) -#define G_IS_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OBJECT)) -#define G_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OBJECT, GParamSpecObject)) +#define G_IS_PARAM_SPEC_CHAR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_CHAR)) +#define G_PARAM_SPEC_CHAR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_CHAR, GParamSpecChar)) +#define G_IS_PARAM_SPEC_UCHAR(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UCHAR)) +#define G_PARAM_SPEC_UCHAR(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UCHAR, GParamSpecUChar)) +#define G_IS_PARAM_SPEC_BOOLEAN(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_BOOLEAN)) +#define G_PARAM_SPEC_BOOLEAN(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_BOOLEAN, GParamSpecBoolean)) +#define G_IS_PARAM_SPEC_INT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_INT)) +#define G_PARAM_SPEC_INT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_INT, GParamSpecInt)) +#define G_IS_PARAM_SPEC_UINT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_UINT)) +#define G_PARAM_SPEC_UINT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_UINT, GParamSpecUInt)) +#define G_IS_PARAM_SPEC_LONG(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_LONG)) +#define G_PARAM_SPEC_LONG(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_LONG, GParamSpecLong)) +#define G_IS_PARAM_SPEC_ULONG(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ULONG)) +#define G_PARAM_SPEC_ULONG(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ULONG, GParamSpecULong)) +#define G_IS_PARAM_SPEC_ENUM(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_ENUM)) +#define G_PARAM_SPEC_ENUM(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_ENUM, GParamSpecEnum)) +#define G_IS_PARAM_SPEC_FLAGS(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLAGS)) +#define G_PARAM_SPEC_FLAGS(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLAGS, GParamSpecFlags)) +#define G_IS_PARAM_SPEC_FLOAT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_FLOAT)) +#define G_PARAM_SPEC_FLOAT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_FLOAT, GParamSpecFloat)) +#define G_IS_PARAM_SPEC_DOUBLE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_DOUBLE)) +#define G_PARAM_SPEC_DOUBLE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_DOUBLE, GParamSpecDouble)) +#define G_IS_PARAM_SPEC_STRING(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_STRING)) +#define G_PARAM_SPEC_STRING(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_STRING, GParamSpecString)) +#define G_IS_PARAM_SPEC_PARAM(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_PARAM)) +#define G_PARAM_SPEC_PARAM(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_PARAM, GParamSpecParam)) +#define G_IS_PARAM_SPEC_POINTER(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_POINTER)) +#define G_PARAM_SPEC_POINTER(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_POINTER, GParamSpecPointer)) +#define G_IS_PARAM_SPEC_CCALLBACK(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_CCALLBACK)) +#define G_PARAM_SPEC_CCALLBACK(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_CCALLBACK, GParamSpecCCallback)) +#define G_IS_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), G_TYPE_PARAM_OBJECT)) +#define G_PARAM_SPEC_OBJECT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), G_TYPE_PARAM_OBJECT, GParamSpecObject)) /* --- typedefs & structures --- */ -typedef struct _GParamSpecChar GParamSpecChar; -typedef struct _GParamSpecUChar GParamSpecUChar; -typedef struct _GParamSpecBoolean GParamSpecBoolean; -typedef struct _GParamSpecInt GParamSpecInt; -typedef struct _GParamSpecUInt GParamSpecUInt; -typedef struct _GParamSpecLong GParamSpecLong; -typedef struct _GParamSpecULong GParamSpecULong; -typedef struct _GParamSpecEnum GParamSpecEnum; -typedef struct _GParamSpecFlags GParamSpecFlags; -typedef struct _GParamSpecFloat GParamSpecFloat; -typedef struct _GParamSpecDouble GParamSpecDouble; -typedef struct _GParamSpecString GParamSpecString; -typedef struct _GParamSpecObject GParamSpecObject; +typedef struct _GParamSpecChar GParamSpecChar; +typedef struct _GParamSpecUChar GParamSpecUChar; +typedef struct _GParamSpecBoolean GParamSpecBoolean; +typedef struct _GParamSpecInt GParamSpecInt; +typedef struct _GParamSpecUInt GParamSpecUInt; +typedef struct _GParamSpecLong GParamSpecLong; +typedef struct _GParamSpecULong GParamSpecULong; +typedef struct _GParamSpecEnum GParamSpecEnum; +typedef struct _GParamSpecFlags GParamSpecFlags; +typedef struct _GParamSpecFloat GParamSpecFloat; +typedef struct _GParamSpecDouble GParamSpecDouble; +typedef struct _GParamSpecString GParamSpecString; +typedef struct _GParamSpecParam GParamSpecParam; +typedef struct _GParamSpecPointer GParamSpecPointer; +typedef struct _GParamSpecCCallback GParamSpecCCallback; +typedef struct _GParamSpecObject GParamSpecObject; struct _GParamSpecChar { GParamSpec parent_instance; @@ -172,6 +181,20 @@ struct _GParamSpecString guint null_fold_if_empty : 1; guint ensure_non_null : 1; }; +struct _GParamSpecParam +{ + GParamSpec parent_instance; + + GType param_type; +}; +struct _GParamSpecPointer +{ + GParamSpec parent_instance; +}; +struct _GParamSpecCCallback +{ + GParamSpec parent_instance; +}; struct _GParamSpecObject { GParamSpec parent_instance; @@ -264,6 +287,19 @@ GParamSpec* g_param_spec_string_c (const gchar *name, const gchar *blurb, const gchar *default_value, GParamFlags flags); +GParamSpec* g_param_spec_param (const gchar *name, + const gchar *nick, + const gchar *blurb, + GType param_type, + GParamFlags flags); +GParamSpec* g_param_spec_pointer (const gchar *name, + const gchar *nick, + const gchar *blurb, + GParamFlags flags); +GParamSpec* g_param_spec_ccallback (const gchar *name, + const gchar *nick, + const gchar *blurb, + GParamFlags flags); GParamSpec* g_param_spec_object (const gchar *name, const gchar *nick, const gchar *blurb, diff --git a/gobject/gsignal.c b/gobject/gsignal.c index b5ce638..dc93b5a 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -22,12 +22,13 @@ #include #include "gsignal.h" - #include "gbsearcharray.h" +#include "gvaluecollector.h" /* pre allocation configurations */ +#define MAX_STACK_VALUES (16) #define BSA_PRE_ALLOC (20) #define HANDLER_PRE_ALLOC (48) #define EMISSION_PRE_ALLOC (16) @@ -131,7 +132,7 @@ static inline Emission* emission_find (Emission *emission_list, guint signal_id, GQuark detail, gpointer instance); -static void signal_emit_R (SignalNode *node, +static gboolean signal_emit_R (SignalNode *node, GQuark detail, gpointer instance, GValue *return_value, @@ -233,21 +234,43 @@ static inline guint signal_id_lookup (GQuark quark, GType itype) { + GType *ifaces, type = itype; + SignalKey key; + guint n_ifaces; + + key.quark = quark; + + /* try looking up signals for this type and its anchestors */ do { - SignalKey key, *signal_key; - - key.itype = itype; - key.quark = quark; + SignalKey *signal_key; + key.itype = type; signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key); if (signal_key) return signal_key->signal_id; - itype = g_type_parent (itype); + type = g_type_parent (type); } - while (itype); + while (type); + + /* no luck, try interfaces it exports */ + ifaces = g_type_interfaces (itype, &n_ifaces); + while (n_ifaces--) + { + SignalKey *signal_key; + + key.itype = ifaces[n_ifaces]; + signal_key = g_bsearch_array_lookup (&g_signal_key_bsa, &key); + + if (signal_key) + { + g_free (ifaces); + return signal_key->signal_id; + } + } + g_free (ifaces); return 0; } @@ -515,7 +538,7 @@ handler_insert (guint signal_id, { HandlerList *hlist; - g_assert (handler->prev == NULL && handler->next == NULL); // FIXME: paranoid + g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */ hlist = handler_list_ensure (signal_id, instance); if (!hlist->handlers) @@ -671,7 +694,7 @@ g_signal_stop_emission (gpointer instance, G_UNLOCK (g_signal_mutex); return; } - if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) + if (node && g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype)) { Emission *emission_list = node->flags & G_SIGNAL_NO_RECURSE ? g_restart_emissions : g_recursive_emissions; Emission *emission = emission_find (emission_list, signal_id, detail, instance); @@ -860,6 +883,44 @@ g_signal_list_ids (GType itype, } guint +g_signal_new (const gchar *signal_name, + GType itype, + GSignalFlags signal_flags, + GClosure *class_closure, + GSignalAccumulator accumulator, + GSignalCMarshaller c_marshaller, + GType return_type, + guint n_params, + ...) +{ + GType *param_types; + guint i; + va_list args; + guint signal_id; + + if (n_params > 0) + { + param_types = g_new (GType, n_params); + + va_start (args, n_params); + + for (i = 0; i < n_params; i++) + param_types[i] = va_arg (args, GType); + + va_end (args); + } + else + param_types = NULL; + + signal_id = g_signal_newv (signal_name, itype, signal_flags, + class_closure, accumulator, c_marshaller, + return_type, n_params, param_types); + g_free (param_types); + + return signal_id; +} + +guint g_signal_newv (const gchar *signal_name, GType itype, GSignalFlags signal_flags, @@ -1023,22 +1084,23 @@ g_signal_connect_closure_by_id (gpointer instance, G_LOCK (g_signal_mutex); node = LOOKUP_SIGNAL_NODE (signal_id); - if (node && detail && !(node->flags & G_SIGNAL_DETAILED)) + if (node) { - g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); - G_UNLOCK (g_signal_mutex); - return 0; - } - if (node && g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) - { - Handler *handler = handler_new (after); - - handler_id = handler->id; - handler->detail = detail; - handler->closure = g_closure_ref (closure); - handler_insert (signal_id, instance, handler); - if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure)) - g_closure_set_marshal (closure, node->c_marshaller); + if (detail && !(node->flags & G_SIGNAL_DETAILED)) + g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); + else if (!g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype)) + g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); + else + { + Handler *handler = handler_new (after); + + handler_id = handler->id; + handler->detail = detail; + handler->closure = g_closure_ref (closure); + handler_insert (signal_id, instance, handler); + if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (closure)) + g_closure_set_marshal (closure, node->c_marshaller); + } } else g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); @@ -1047,6 +1109,97 @@ g_signal_connect_closure_by_id (gpointer instance, return handler_id; } +guint +g_signal_connect_closure (gpointer instance, + const gchar *detailed_signal, + GClosure *closure, + gboolean after) +{ + guint signal_id, handler_id = 0; + GQuark detail = 0; + GType itype; + + g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); + g_return_val_if_fail (detailed_signal != NULL, 0); + g_return_val_if_fail (closure != NULL, 0); + + G_LOCK (g_signal_mutex); + itype = G_TYPE_FROM_INSTANCE (instance); + signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE); + if (signal_id) + { + SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id); + + if (detail && !(node->flags & G_SIGNAL_DETAILED)) + g_warning ("%s: signal `%s' does not support details", G_STRLOC, detailed_signal); + else if (!g_type_is_a (itype, node->itype)) + g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance); + else + { + Handler *handler = handler_new (after); + + handler_id = handler->id; + handler->detail = detail; + handler->closure = g_closure_ref (closure); + handler_insert (signal_id, instance, handler); + if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure)) + g_closure_set_marshal (handler->closure, node->c_marshaller); + } + } + else + g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance); + G_UNLOCK (g_signal_mutex); + + return handler_id; +} + +guint +g_signal_connect_data (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + gboolean swapped, + gboolean after) +{ + guint signal_id, handler_id = 0; + GQuark detail = 0; + GType itype; + + g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0); + g_return_val_if_fail (detailed_signal != NULL, 0); + g_return_val_if_fail (c_handler != NULL, 0); + + G_LOCK (g_signal_mutex); + itype = G_TYPE_FROM_INSTANCE (instance); + signal_id = signal_parse_name (detailed_signal, itype, &detail, TRUE); + if (signal_id) + { + SignalNode *node = LOOKUP_SIGNAL_NODE (signal_id); + + if (detail && !(node->flags & G_SIGNAL_DETAILED)) + g_warning ("%s: signal `%s' does not support details", G_STRLOC, detailed_signal); + else if (!g_type_is_a (itype, node->itype)) + g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance); + else + { + Handler *handler = handler_new (after); + + handler_id = handler->id; + handler->detail = detail; + handler->closure = g_closure_ref ((swapped ? g_cclosure_new_swap : g_cclosure_new) (c_handler, data, destroy_data)); + handler_insert (signal_id, instance, handler); + if (node->c_marshaller && G_CLOSURE_NEEDS_MARSHAL (handler->closure)) + g_closure_set_marshal (handler->closure, node->c_marshaller); + } + } + else + g_warning ("%s: signal `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance); + G_UNLOCK (g_signal_mutex); + + return handler_id; +} + void g_signal_handler_block (gpointer instance, guint handler_id) @@ -1342,27 +1495,27 @@ g_signal_emitv (const GValue *instance_and_params, GQuark detail, GValue *return_value) { - SignalNode *node; - gpointer instance; const GValue *param_values; + gpointer instance; + SignalNode *node; guint i; g_return_if_fail (instance_and_params != NULL); instance = g_value_get_as_pointer (instance_and_params); g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); g_return_if_fail (signal_id > 0); - + param_values = instance_and_params + 1; G_LOCK (g_signal_mutex); node = LOOKUP_SIGNAL_NODE (signal_id); -#ifndef G_DISABLE_CHECKS - if (!node || !g_type_conforms_to (G_TYPE_FROM_INSTANCE (instance), node->itype)) + if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype)) { g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); G_UNLOCK (g_signal_mutex); return; } +#ifndef G_DISABLE_CHECKS if (detail && !(node->flags & G_SIGNAL_DETAILED)) { g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); @@ -1372,7 +1525,8 @@ g_signal_emitv (const GValue *instance_and_params, for (i = 0; i < node->n_params; i++) if (!G_VALUE_HOLDS (param_values + i, node->param_types[i])) { - g_critical (G_STRLOC ": value for `%s' parameter %u for signal \"%s\" is of type `%s'", + g_critical ("%s: value for `%s' parameter %u for signal \"%s\" is of type `%s'", + G_STRLOC, g_type_name (node->param_types[i]), i, node->name, @@ -1384,7 +1538,8 @@ g_signal_emitv (const GValue *instance_and_params, { if (!return_value) { - g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is (NULL)", + g_critical ("%s: return value `%s' for signal \"%s\" is (NULL)", + G_STRLOC, g_type_name (node->return_type), node->name); G_UNLOCK (g_signal_mutex); @@ -1392,7 +1547,8 @@ g_signal_emitv (const GValue *instance_and_params, } else if (!node->accumulator && !G_VALUE_HOLDS (return_value, node->return_type)) { - g_critical (G_STRLOC ": return value `%s' for signal \"%s\" is of type `%s'", + g_critical ("%s: return value `%s' for signal \"%s\" is of type `%s'", + G_STRLOC, g_type_name (node->return_type), node->name, G_VALUE_TYPE_NAME (return_value)); @@ -1403,13 +1559,147 @@ g_signal_emitv (const GValue *instance_and_params, else return_value = NULL; #endif /* !G_DISABLE_CHECKS */ - + signal_emit_R (node, detail, instance, return_value, instance_and_params); - G_UNLOCK (g_signal_mutex); } -static void +void +g_signal_emit_valist (gpointer instance, + guint signal_id, + GQuark detail, + va_list var_args) +{ + GValue *instance_and_params, stack_values[MAX_STACK_VALUES], *free_me = NULL; + GValue *param_values; + SignalNode *node; + guint i; + + g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); + g_return_if_fail (signal_id > 0); + + G_LOCK (g_signal_mutex); + node = LOOKUP_SIGNAL_NODE (signal_id); + if (!node || !g_type_is_a (G_TYPE_FROM_INSTANCE (instance), node->itype)) + { + g_warning ("%s: signal id `%u' is invalid for instance `%p'", G_STRLOC, signal_id, instance); + G_UNLOCK (g_signal_mutex); + return; + } +#ifndef G_DISABLE_CHECKS + if (detail && !(node->flags & G_SIGNAL_DETAILED)) + { + g_warning ("%s: signal id `%u' does not support detail (%u)", G_STRLOC, signal_id, detail); + G_UNLOCK (g_signal_mutex); + return; + } +#endif /* !G_DISABLE_CHECKS */ + + if (node->n_params < MAX_STACK_VALUES) + instance_and_params = stack_values; + else + { + free_me = g_new (GValue, node->n_params + 1); + instance_and_params = free_me; + } + param_values = instance_and_params + 1; + for (i = 0; i < node->n_params; i++) + { + gchar *error; + + param_values[i].g_type = 0; + g_value_init (param_values + i, node->param_types[i]); + G_VALUE_COLLECT (param_values + i, var_args, &error); + if (error) + { + g_warning ("%s: %s", G_STRLOC, error); + g_free (error); + + /* we purposely leak the value here, it might not be + * in a sane state if an error condition occoured + */ + while (i--) + g_value_unset (param_values + i); + + G_UNLOCK (g_signal_mutex); + g_free (free_me); + return; + } + } + instance_and_params->g_type = 0; + g_value_init (instance_and_params, node->itype); + g_value_set_instance (instance_and_params, instance); + if (node->return_type == G_TYPE_NONE) + signal_emit_R (node, detail, instance, NULL, instance_and_params); + else + { + GValue return_value = { 0, }; + gchar *error = NULL; + + g_value_init (&return_value, node->return_type); + if (signal_emit_R (node, detail, instance, &return_value, instance_and_params)) + G_VALUE_LCOPY (&return_value, var_args, &error); + if (!error) + g_value_unset (&return_value); + else + { + g_warning ("%s: %s", G_STRLOC, error); + g_free (error); + + /* we purposely leak the value here, it might not be + * in a sane state if an error condition occoured + */ + } + } + for (i = 0; i < node->n_params; i++) + g_value_unset (param_values + i); + g_value_unset (instance_and_params); + if (free_me) + g_free (free_me); + G_UNLOCK (g_signal_mutex); +} + +void +g_signal_emit (gpointer instance, + guint signal_id, + GQuark detail, + ...) +{ + va_list var_args; + + va_start (var_args, detail); + g_signal_emit_valist (instance, signal_id, detail, var_args); + va_end (var_args); +} + +void +g_signal_emit_by_name (gpointer instance, + const gchar *detailed_signal, + ...) +{ + GQuark detail = 0; + guint signal_id; + + g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); + g_return_if_fail (detailed_signal != NULL); + + G_LOCK (g_signal_mutex); + signal_id = signal_parse_name (detailed_signal, G_TYPE_FROM_INSTANCE (instance), &detail, TRUE); + G_UNLOCK (g_signal_mutex); + + if (signal_id) + { + va_list var_args; + + va_start (var_args, detailed_signal); + g_signal_emit_valist (instance, signal_id, detail, var_args); + va_end (var_args); + } + else + g_warning ("%s: signal name `%s' is invalid for instance `%p'", G_STRLOC, detailed_signal, instance); +} + +static gboolean signal_emit_R (SignalNode *node, GQuark detail, gpointer instance, @@ -1422,9 +1712,10 @@ signal_emit_R (SignalNode *node, GClosure *class_closure; HandlerList *hlist; Handler *handler_list = NULL; - GValue accu; + GValue accu = { 0, }; gboolean accu_used = FALSE; guint signal_id = node->signal_id; + gboolean return_value_altered = FALSE; if (node->flags & G_SIGNAL_NO_RECURSE) { @@ -1433,18 +1724,14 @@ signal_emit_R (SignalNode *node, if (emission) { *emission->state_p = EMISSION_RESTART; - return; + return return_value_altered; } } ihint.signal_id = node->signal_id; ihint.detail = detail; accumulator = node->accumulator; if (accumulator) - { - G_UNLOCK (g_signal_mutex); - g_value_init (&accu, node->return_type); - G_LOCK (g_signal_mutex); - } + g_value_init (&accu, node->return_type); emission_push ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, signal_id, detail, instance, &emission_state); class_closure = node->class_closure; @@ -1486,6 +1773,7 @@ signal_emit_R (SignalNode *node, instance_and_params, &ihint); G_LOCK (g_signal_mutex); + return_value_altered = TRUE; if (emission_state == EMISSION_STOP) goto EMIT_CLEANUP; @@ -1545,6 +1833,7 @@ signal_emit_R (SignalNode *node, instance_and_params, &ihint); G_LOCK (g_signal_mutex); + return_value_altered = TRUE; tmp = emission_state == EMISSION_RUN ? handler->next : NULL; } @@ -1593,6 +1882,7 @@ signal_emit_R (SignalNode *node, instance_and_params, &ihint); G_LOCK (g_signal_mutex); + return_value_altered = TRUE; if (emission_state == EMISSION_STOP) goto EMIT_CLEANUP; @@ -1634,6 +1924,7 @@ signal_emit_R (SignalNode *node, instance_and_params, &ihint); G_LOCK (g_signal_mutex); + return_value_altered = TRUE; tmp = emission_state == EMISSION_RUN ? handler->next : NULL; } @@ -1692,9 +1983,12 @@ signal_emit_R (SignalNode *node, emission_pop ((node->flags & G_SIGNAL_NO_RECURSE) ? &g_restart_emissions : &g_recursive_emissions, &emission_state); if (accumulator) - { - G_UNLOCK (g_signal_mutex); - g_value_unset (&accu); - G_LOCK (g_signal_mutex); - } + g_value_unset (&accu); + + return return_value_altered; } + + +/* compile standard marshallers */ +#include "gvaluetypes.h" +#include "gmarshal.c" diff --git a/gobject/gsignal.h b/gobject/gsignal.h index 9d2c5ca..d054595 100644 --- a/gobject/gsignal.h +++ b/gobject/gsignal.h @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef __cplusplus @@ -86,9 +87,18 @@ struct _GSignalQuery /* --- signals --- */ +guint g_signal_new (const gchar *signal_name, + GType itype, + GSignalFlags signal_flags, + GClosure *class_closure, + GSignalAccumulator accumulator, + GSignalCMarshaller c_marshaller, + GType return_type, + guint n_params, + ...); guint g_signal_newv (const gchar *signal_name, GType itype, - GSignalFlags signal_flags, + GSignalFlags signal_flags, GClosure *class_closure, GSignalAccumulator accumulator, GSignalCMarshaller c_marshaller, @@ -99,6 +109,17 @@ void g_signal_emitv (const GValue *instance_and_params, guint signal_id, GQuark detail, GValue *return_value); +void g_signal_emit_valist (gpointer instance, + guint signal_id, + GQuark detail, + va_list var_args); +void g_signal_emit (gpointer instance, + guint signal_id, + GQuark detail, + ...); +void g_signal_emit_by_name (gpointer instance, + const gchar *detailed_signal, + ...); guint g_signal_lookup (const gchar *name, GType itype); gchar* g_signal_name (guint signal_id); @@ -127,6 +148,17 @@ guint g_signal_connect_closure_by_id (gpointer instance, GQuark detail, GClosure *closure, gboolean after); +guint g_signal_connect_closure (gpointer instance, + const gchar *detailed_signal, + GClosure *closure, + gboolean after); +guint g_signal_connect_data (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + gboolean swapped, + gboolean after); void g_signal_handler_block (gpointer instance, guint handler_id); void g_signal_handler_unblock (gpointer instance, diff --git a/gobject/gtype.c b/gobject/gtype.c index 7924d87..42842dd 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -21,7 +21,7 @@ #include "gtypeplugin.h" #include -#define FIXME_DISABLE_PREALLOCATIONS +#undef FIXME_DISABLE_PREALLOCATIONS /* NOTE: some functions (some internal variants and exported ones) * invalidate data portions of the TypeNodes. if external functions/callbacks @@ -173,7 +173,7 @@ static GQuark quark_type_flags = 0; /* --- externs --- */ -const char *g_log_domain_gobject = "GLib-Object"; +const char *g_log_domain_gruntime = "GRuntime"; /* --- type nodes --- */ @@ -796,7 +796,7 @@ type_data_make (TypeNode *node, *vtable = *value_table; node->data->common.value_table = vtable; - g_assert (node->data->common.value_table != NULL); /* FIXME: paranoid */ + g_assert (node->data->common.value_table != NULL); /* paranoid */ } static inline void @@ -1024,7 +1024,7 @@ g_type_free_instance (GTypeInstance *instance) } instance->g_class = NULL; - memset (instance, 0xaa, node->data->instance.instance_size); // FIXME + memset (instance, 0xaa, node->data->instance.instance_size); // FIXME: debugging hack if (node->data->instance.n_preallocs) g_chunk_free (instance, node->data->instance.mem_chunk); else @@ -1667,6 +1667,7 @@ g_type_next_base (GType type, return 0; } +#if 0 gboolean g_type_is_a (GType type, GType is_a_type) @@ -1688,10 +1689,11 @@ g_type_is_a (GType type, return FALSE; } +#endif gboolean -g_type_conforms_to (GType type, - GType iface_type) +g_type_is_a (GType type, + GType iface_type) { if (type != iface_type) { @@ -1807,7 +1809,7 @@ g_type_get_qdata (GType type, QData *qdatas = gdata->qdatas - 1; guint n_qdatas = gdata->n_qdatas; - do /* FIXME: should optimize qdata lookups for <= 4 */ + do { guint i; QData *check; @@ -1943,12 +1945,12 @@ g_type_fundamental_last (void) } gboolean -g_type_instance_conforms_to (GTypeInstance *type_instance, - GType iface_type) +g_type_instance_is_a (GTypeInstance *type_instance, + GType iface_type) { return (type_instance && type_instance->g_class && G_TYPE_IS_INSTANTIATABLE (type_instance->g_class->g_type) && - g_type_conforms_to (type_instance->g_class->g_type, iface_type)); + g_type_is_a (type_instance->g_class->g_type, iface_type)); } gboolean @@ -1960,8 +1962,8 @@ g_type_class_is_a (GTypeClass *type_class, } gboolean -g_type_value_conforms_to (GValue *value, - GType type) +g_type_value_is_a (GValue *value, + GType type) { TypeNode *node; @@ -1974,7 +1976,7 @@ g_type_value_conforms_to (GValue *value, #endif if (!node || !node->data || node->data->common.ref_count < 1 || !node->data->common.value_table->value_init || - !g_type_conforms_to (value->g_type, type)) + !g_type_is_a (value->g_type, type)) return FALSE; return TRUE; @@ -1983,7 +1985,7 @@ g_type_value_conforms_to (GValue *value, gboolean g_type_check_value (GValue *value) { - return value && g_type_value_conforms_to (value, value->g_type); + return value && g_type_value_is_a (value, value->g_type); } GTypeInstance* @@ -2009,7 +2011,7 @@ g_type_check_instance_cast (GTypeInstance *type_instance, type_descriptive_name (iface_type)); return type_instance; } - if (!g_type_conforms_to (type_instance->g_class->g_type, iface_type)) + if (!g_type_is_a (type_instance->g_class->g_type, iface_type)) { g_warning ("invalid cast from `%s' to `%s'", type_descriptive_name (type_instance->g_class->g_type), @@ -2125,7 +2127,7 @@ g_type_init (void) memset (&info, 0, sizeof (info)); node = type_node_fundamental_new (G_TYPE_INTERFACE, "GInterface", G_TYPE_FLAG_DERIVABLE); type = NODE_TYPE (node); - type_data_make (node, &info, NULL); /* FIXME */ + type_data_make (node, &info, NULL); g_assert (type == G_TYPE_INTERFACE); /* G_TYPE_TYPE_PLUGIN diff --git a/gobject/gtype.h b/gobject/gtype.h index 89ecd96..bbbf36b 100644 --- a/gobject/gtype.h +++ b/gobject/gtype.h @@ -19,7 +19,7 @@ #ifndef __G_TYPE_H__ #define __G_TYPE_H__ -extern const char *g_log_domain_gobject; +extern const char *g_log_domain_gruntime; #include @@ -62,6 +62,7 @@ typedef enum /*< skip >*/ G_TYPE_PARAM, G_TYPE_BOXED, G_TYPE_POINTER, + G_TYPE_CCALLBACK, G_TYPE_OBJECT, /* the following reserved ids should vanish soon */ @@ -79,7 +80,6 @@ typedef enum /*< skip >*/ G_TYPE_LAST_RESERVED_FUNDAMENTAL, /* derived type ids */ - /* FIXME: G_TYPE_PARAM_INTERFACE */ G_TYPE_PARAM_CHAR = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 1), G_TYPE_PARAM_UCHAR = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 2), G_TYPE_PARAM_BOOLEAN = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 3), @@ -92,8 +92,10 @@ typedef enum /*< skip >*/ G_TYPE_PARAM_FLOAT = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 10), G_TYPE_PARAM_DOUBLE = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 11), G_TYPE_PARAM_STRING = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 12), - /* FIXME: G_TYPE_PARAM_PARAM */ - G_TYPE_PARAM_OBJECT = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 13) + G_TYPE_PARAM_PARAM = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 13), + G_TYPE_PARAM_POINTER = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 14), + G_TYPE_PARAM_CCALLBACK = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 15), + G_TYPE_PARAM_OBJECT = G_TYPE_DERIVE_ID (G_TYPE_PARAM, 16) } GTypeFundamentals; @@ -174,8 +176,6 @@ GType g_type_next_base (GType type, GType base_type); gboolean g_type_is_a (GType type, GType is_a_type); -gboolean g_type_conforms_to (GType type, - GType iface_type); guint g_type_fundamental_branch_last (GType type); gpointer g_type_class_ref (GType type); gpointer g_type_class_peek (GType type); @@ -317,10 +317,10 @@ gboolean g_type_class_is_a (GTypeClass *g_class, GType is_a_type); GTypeInstance* g_type_check_instance_cast (GTypeInstance *instance, GType iface_type); -gboolean g_type_instance_conforms_to (GTypeInstance *instance, +gboolean g_type_instance_is_a (GTypeInstance *instance, GType iface_type); gboolean g_type_check_value (GValue *value); -gboolean g_type_value_conforms_to (GValue *value, +gboolean g_type_value_is_a (GValue *value, GType type); gboolean g_type_check_instance (GTypeInstance *instance); GTypeValueTable* g_type_value_table_peek (GType type); @@ -336,9 +336,9 @@ GTypeValueTable* g_type_value_table_peek (GType type); # define _G_TYPE_CCC(cp, gt, ct) ((ct*) cp) #endif /* G_DISABLE_CAST_CHECKS */ #define _G_TYPE_CHI(ip) (g_type_check_instance ((GTypeInstance*) ip)) -#define _G_TYPE_CIT(ip, gt) (g_type_instance_conforms_to ((GTypeInstance*) ip, gt)) +#define _G_TYPE_CIT(ip, gt) (g_type_instance_is_a ((GTypeInstance*) ip, gt)) #define _G_TYPE_CCT(cp, gt) (g_type_class_is_a ((GTypeClass*) cp, gt)) -#define _G_TYPE_CVT(vl, gt) (g_type_value_conforms_to ((GValue*) vl, gt)) +#define _G_TYPE_CVT(vl, gt) (g_type_value_is_a ((GValue*) vl, gt)) #define _G_TYPE_CHV(vl) (g_type_check_value ((GValue*) vl)) #define _G_TYPE_IGC(ip, gt, ct) ((ct*) (((GTypeInstance*) ip)->g_class)) #define _G_TYPE_IGI(ip, gt, ct) ((ct*) g_type_interface_peek (((GTypeInstance*) ip)->g_class, gt)) diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c index cef7499..858af80 100644 --- a/gobject/gtypemodule.c +++ b/gobject/gtypemodule.c @@ -406,7 +406,7 @@ g_type_module_add_interface (GTypeModule *module, g_return_if_fail (module != NULL); g_return_if_fail (interface_info != NULL); - if (g_type_conforms_to (instance_type, interface_type)) + if (g_type_is_a (instance_type, interface_type)) { GTypePlugin *old_plugin = g_type_interface_get_plugin (instance_type, interface_type); diff --git a/gobject/gvalue.c b/gobject/gvalue.c index e6a2dbd..466c13d 100644 --- a/gobject/gvalue.c +++ b/gobject/gvalue.c @@ -20,6 +20,7 @@ #include #include "gvalue.h" +#include "gvaluecollector.h" /* --- typedefs & structures --- */ @@ -66,7 +67,7 @@ g_value_copy (const GValue *src_value, g_return_if_fail (G_IS_VALUE (src_value)); g_return_if_fail (G_IS_VALUE (dest_value)); g_return_if_fail (g_type_is_a (G_VALUE_TYPE (src_value), G_VALUE_TYPE (dest_value))); - + value_table = g_type_value_table_peek (G_VALUE_TYPE (dest_value)); if (!value_table) g_return_if_fail (g_type_value_table_peek (G_VALUE_TYPE (dest_value)) != NULL); @@ -111,6 +112,54 @@ g_value_get_as_pointer (const GValue *value) } void +g_value_set_instance (GValue *value, + gpointer instance) +{ + g_return_if_fail (G_IS_VALUE (value)); + + g_value_reset (value); + if (instance) + { + GType g_type = G_VALUE_TYPE (value); + GTypeValueTable *value_table = g_type_value_table_peek (g_type); + GTypeCValue cvalue = { 0, }; + guint nth_value = 0; + guint collect_type = value_table->collect_type; + gchar *error_msg; + + g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance)); + g_return_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (instance), G_VALUE_TYPE (value))); + g_return_if_fail (value_table->collect_type == G_VALUE_COLLECT_POINTER); + + cvalue.v_pointer = instance; + error_msg = value_table->collect_value (value, nth_value++, &collect_type, &cvalue); + + /* this shouldn't be triggered, instance types should collect just one pointer, + * but since we have to follow the calling conventions for collect_value(), + * we can attempt to feed them with 0s if they insist on extra args. + */ + while (collect_type && !error_msg) + { + memset (&cvalue, 0, sizeof (cvalue)); + error_msg = value_table->collect_value (value, nth_value++, &collect_type, &cvalue); + } + + if (error_msg) + { + g_warning ("%s: %s", G_STRLOC, error_msg); + g_free (error_msg); + + /* we purposely leak the value here, it might not be + * in a sane state if an error condition occoured + */ + memset (value, 0, sizeof (*value)); + value->g_type = g_type; + value_table->value_init (value); + } + } +} + +void g_value_unset (GValue *value) { GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value)); @@ -127,11 +176,12 @@ g_value_unset (GValue *value) void g_value_reset (GValue *value) { - GTypeValueTable *value_table = g_type_value_table_peek (G_VALUE_TYPE (value)); + GTypeValueTable *value_table; GType g_type; g_return_if_fail (G_IS_VALUE (value)); + value_table = g_type_value_table_peek (G_VALUE_TYPE (value)); g_type = G_VALUE_TYPE (value); if (value_table->value_free) diff --git a/gobject/gvalue.h b/gobject/gvalue.h index be68eba..364e88a 100644 --- a/gobject/gvalue.h +++ b/gobject/gvalue.h @@ -69,6 +69,8 @@ void g_value_reset (GValue *value); void g_value_unset (GValue *value); gboolean g_value_fits_pointer (const GValue *value); gpointer g_value_get_as_pointer (const GValue *value); +void g_value_set_instance (GValue *value, + gpointer instance); /* --- implementation details --- */ diff --git a/gobject/gvaluecollector.h b/gobject/gvaluecollector.h index 7bbdfc0..d85e8d6 100644 --- a/gobject/gvaluecollector.h +++ b/gobject/gvaluecollector.h @@ -71,9 +71,8 @@ G_STMT_START { \ g_value_reset (_value); \ while (_collect_type && !_error_msg) \ { \ - GTypeCValue _cvalue; \ + GTypeCValue _cvalue = { 0, }; \ \ - memset (&_cvalue, 0, sizeof (_cvalue)); \ switch (_collect_type) \ { \ case G_VALUE_COLLECT_INT: \ @@ -117,9 +116,8 @@ G_STMT_START { \ \ while (_lcopy_type && !_error_msg) \ { \ - GTypeCValue _cvalue; \ + GTypeCValue _cvalue = { 0, }; \ \ - memset (&_cvalue, 0, sizeof (_cvalue)); \ switch (_lcopy_type) \ { \ case G_VALUE_COLLECT_INT: \ diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c index e3406aa..8ead3a5 100644 --- a/gobject/gvaluetypes.c +++ b/gobject/gvaluetypes.c @@ -264,7 +264,7 @@ value_string_lcopy_value (const GValue *value, static void value_pointer_init (GValue *value) { - value->data[0].v_pointer = 0; + value->data[0].v_pointer = NULL; } static void @@ -309,6 +309,76 @@ value_pointer_lcopy_value (const GValue *value, return NULL; } +static void +value_ccallback_init (GValue *value) +{ + value->data[0].v_pointer = NULL; + value->data[1].v_pointer = NULL; +} + +static void +value_ccallback_copy (const GValue *src_value, + GValue *dest_value) +{ + dest_value->data[0].v_pointer = src_value->data[0].v_pointer; + dest_value->data[1].v_pointer = src_value->data[1].v_pointer; +} + +static gchar* +value_ccallback_collect_value (GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value) +{ + gchar *error = NULL; + + switch (nth_value) + { + case 0: + value->data[0].v_pointer = collect_value->v_pointer; + *collect_type = G_VALUE_COLLECT_POINTER; + if (!value->data[0].v_pointer) + error = g_strconcat ("invalid (NULL) pointer callback function for value type `", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + break; + case 1: + value->data[1].v_pointer = collect_value->v_pointer; + *collect_type = 0; + break; + } + + return error; +} + +static gchar* +value_ccallback_lcopy_value (const GValue *value, + guint nth_value, + GType *collect_type, + GTypeCValue *collect_value) +{ + gpointer *pointer_p = collect_value->v_pointer; + + if (!pointer_p) + return g_strdup_printf ("%s location for `%s' passed as NULL", + nth_value ? "data" : "callback", + G_VALUE_TYPE_NAME (value)); + switch (nth_value) + { + case 0: + *pointer_p = value->data[0].v_pointer; + *collect_type = G_VALUE_COLLECT_POINTER; + break; + case 1: + *pointer_p = value->data[1].v_pointer; + *collect_type = 0; + break; + } + + return NULL; +} + /* --- type initialization --- */ void @@ -478,6 +548,24 @@ g_value_types_init (void) /* sync with gtype.c */ type = g_type_register_fundamental (G_TYPE_POINTER, "gpointer", &info, &finfo, 0); g_assert (type == G_TYPE_POINTER); } + + /* G_TYPE_CCALLBACK + */ + { + static const GTypeValueTable value_table = { + value_ccallback_init, /* value_init */ + NULL, /* value_free */ + value_ccallback_copy, /* value_copy */ + NULL, /* value_peek_pointer */ + G_VALUE_COLLECT_POINTER, /* collect_type */ + value_ccallback_collect_value, /* collect_value */ + G_VALUE_COLLECT_POINTER, /* lcopy_type */ + value_ccallback_lcopy_value, /* lcopy_value */ + }; + info.value_table = &value_table; + type = g_type_register_fundamental (G_TYPE_CCALLBACK, "GCCallback", &info, &finfo, 0); + g_assert (type == G_TYPE_CCALLBACK); + } } @@ -692,3 +780,27 @@ g_value_get_pointer (const GValue *value) return value->data[0].v_pointer; } + +void +g_value_set_ccallback (GValue *value, + gpointer callback_func, + gpointer callback_data) +{ + g_return_if_fail (G_IS_VALUE_CCALLBACK (value)); + + value->data[0].v_pointer = callback_func; + value->data[1].v_pointer = callback_data; +} + +void +g_value_get_ccallback (const GValue *value, + gpointer *callback_func, + gpointer *callback_data) +{ + g_return_if_fail (G_IS_VALUE_CCALLBACK (value)); + + if (callback_func) + *callback_func = value->data[0].v_pointer; + if (callback_data) + *callback_data = value->data[1].v_pointer; +} diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h index 9f0b143..a7405cc 100644 --- a/gobject/gvaluetypes.h +++ b/gobject/gvaluetypes.h @@ -42,6 +42,7 @@ extern "C" { #define G_IS_VALUE_DOUBLE(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_DOUBLE)) #define G_IS_VALUE_STRING(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_STRING)) #define G_IS_VALUE_POINTER(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_POINTER)) +#define G_IS_VALUE_CCALLBACK(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_CCALLBACK)) /* --- prototypes --- */ @@ -81,7 +82,12 @@ gchar* g_value_dup_string (const GValue *value); void g_value_set_pointer (GValue *value, gpointer v_pointer); gpointer g_value_get_pointer (const GValue *value); - +void g_value_set_ccallback (GValue *value, + gpointer callback_func, + gpointer callback_data); +void g_value_get_ccallback (const GValue *value, + gpointer *callback_func, + gpointer *callback_data); diff --git a/gobject/makefile.mingw.in b/gobject/makefile.mingw.in index a0f0669..5608e14 100644 --- a/gobject/makefile.mingw.in +++ b/gobject/makefile.mingw.in @@ -16,7 +16,7 @@ GLIB_VER = @GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@ # Nothing much configurable below INCLUDES = -I .. -I . -DEFINES = -DHAVE_CONFIG_H -DGOBJECT_COMPILATION -DG_LOG_DOMAIN=g_log_domain_gobject +DEFINES = -DHAVE_CONFIG_H -DGOBJECT_COMPILATION -DG_LOG_DOMAIN=g_log_domain_gruntime BUILD_DLL = ../build-dll diff --git a/gobject/makefile.msc.in b/gobject/makefile.msc.in index ce8ce8e..b804ace 100644 --- a/gobject/makefile.msc.in +++ b/gobject/makefile.msc.in @@ -13,7 +13,7 @@ GLIB_VER = @GLIB_MAJOR_VERSION@.@GLIB_MINOR_VERSION@ # Nothing much configurable below INCLUDES = -I .. -I . -DEFINES = -DHAVE_CONFIG_H -DGOBJECT_COMPILATION -DG_LOG_DOMAIN=g_log_domain_gobject +DEFINES = -DHAVE_CONFIG_H -DGOBJECT_COMPILATION -DG_LOG_DOMAIN=g_log_domain_gruntime all : \ gobject-$(GLIB_VER).dll \