[perl-Glib] Wrap g_log_set_default_handler and g_log_default_handler
- From: Torsten Schönfeld <tsch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [perl-Glib] Wrap g_log_set_default_handler and g_log_default_handler
- Date: Sun, 12 Dec 2010 14:58:15 +0000 (UTC)
commit 973307e7c7b9b17321278f726b092d40de2816c4
Author: Kevin Ryde <user42 zip com au>
Date: Sun Dec 12 15:45:55 2010 +0100
Wrap g_log_set_default_handler and g_log_default_handler
https://bugzilla.gnome.org/show_bug.cgi?id=579103
GLog.xs | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
NEWS | 1 +
t/a.t | 67 ++++++++++++++++++++++++++++++++-
3 files changed, 185 insertions(+), 11 deletions(-)
---
diff --git a/GLog.xs b/GLog.xs
index c123668..d1e3adf 100644
--- a/GLog.xs
+++ b/GLog.xs
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2005 by the gtk2-perl team (see the file AUTHORS for
+ * Copyright (C) 2003-2005, 2009 by the gtk2-perl team (see the file AUTHORS for
* the full list)
*
* This library is free software; you can redistribute it and/or modify it
@@ -85,6 +85,17 @@ SvGLogLevelFlags (SV * sv)
return gperl_convert_flags (g_log_level_flags_get_type (), sv);
}
+/* for GLogFunc style, to be invoked by gperl_log_func() below */
+static GPerlCallback *
+gperl_log_callback_new (SV *log_func, SV *user_data)
+{
+ GType param_types[3];
+ param_types[0] = G_TYPE_STRING;
+ param_types[1] = g_log_level_flags_get_type ();
+ param_types[2] = G_TYPE_STRING;
+ return gperl_callback_new (log_func, user_data,
+ 3, param_types, G_TYPE_NONE);
+}
static void
gperl_log_func (const gchar *log_domain,
GLogLevelFlags log_level,
@@ -95,6 +106,13 @@ gperl_log_func (const gchar *log_domain,
log_domain, log_level, message);
}
+#if GLIB_CHECK_VERSION (2, 6, 0)
+/* the GPerlCallback currently installed through
+ g_log_set_default_handler(), or NULL if no such */
+static GPerlCallback *gperl_log_default_handler_callback = NULL;
+G_LOCK_DEFINE_STATIC (gperl_log_default_handler_callback);
+#endif
+
void
gperl_log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
@@ -191,19 +209,19 @@ BOOT:
=arg log_func (subroutine) handler function
+$log_func will be called as
+
+ &$log_func ($log_domain, $log_levels, $message, $user_data);
+
+where $log_domain is the name requested and $log_levels is a
+Glib::LogLevelFlags of level and flags being reported.
=cut
guint
g_log_set_handler (class, gchar_ornull * log_domain, SV * log_levels, SV * log_func, SV * user_data=NULL)
PREINIT:
GPerlCallback * callback;
- GType param_types[3];
CODE:
- param_types[0] = G_TYPE_STRING;
- param_types[1] = g_log_level_flags_get_type ();
- param_types[2] = G_TYPE_STRING;
-
- callback = gperl_callback_new (log_func, user_data,
- 3, param_types, G_TYPE_NONE);
+ callback = gperl_log_callback_new (log_func, user_data);
RETVAL = g_log_set_handler (log_domain,
SvGLogLevelFlags (log_levels),
gperl_log_func, callback);
@@ -223,7 +241,99 @@ g_log_remove_handler (class, gchar_ornull *log_domain, guint handler_id);
C_ARGS:
log_domain, handler_id
-##void g_log_default_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer unused_data);
+=for apidoc __function__
+=for signature Glib::Log::default_handler ($log_domain, $log_level, $message, ...)
+=for arg ... possible "userdata" argument ignored
+The arguments are the same as taken by the function for set_handler or
+set_default_handler.
+=cut
+void g_log_default_handler (const gchar *log_domain, SV *log_level, const gchar *message, ...);
+ CODE:
+ g_log_default_handler (log_domain, SvGLogLevelFlags(log_level),
+ message, NULL);
+
+#if GLIB_CHECK_VERSION (2, 6, 0)
+
+##GLogFunc g_log_set_default_handler (GLogFunc log_func, gpointer user_data);
+=for apidoc
+=for signature prev_log_func = Glib->set_default_handler ($log_func, $user_data)
+=arg log_func (subroutine) handler function or undef
+Install log_func as the default log handler. log_func is called for
+anything which doesn't otherwise have a handler (either
+Glib::Log->set_handler, or the L<Glib::xsapi|Glib::xsapi>
+gperl_handle_logs_for),
+
+ &$log_func ($log_domain, $log_levels, $message, $user_data)
+
+where $log_domain is a string, and $log_levels is a
+Glib::LogLevelFlags of level and flags being reported.
+
+If log_func is \&Glib::Log::default_handler or undef then Glib's
+default handler is set.
+
+The return value from C<set_default_handler> is the previous handler.
+This is \&Glib::Log::default_handler for Glib's default, otherwise a
+Perl function previously installed. If the handler is some other
+non-Perl function then currently the return is undef, but perhaps that
+will change to some wrapped thing, except that without associated
+userdata there's very little which could be done with it (it couldn't
+be reinstalled later without its userdata).
+=cut
+SV *
+g_log_set_default_handler (class, SV * log_func, SV * user_data=NULL)
+ PREINIT:
+ GLogFunc new_func = &g_log_default_handler;
+ GLogFunc old_func;
+ GPerlCallback *new_callback = NULL;
+ GPerlCallback *old_callback;
+ CODE:
+ if (gperl_sv_is_defined (log_func)) {
+ /* check for log_func == \&Glib::Log::default_handler and
+ * turn that into g_log_default_handler() directly, rather
+ * than making a callback into perl and out again. This is
+ * mainly an optimization, but if something weird has
+ * happened then the direct C function will be much more
+ * likely to work.
+ */
+ HV *st;
+ GV *gv;
+ CV *cv = sv_2cv(log_func, &st, &gv, 0);
+ if (cv && CvXSUB(cv) == XS_Glib__Log_default_handler) {
+ /* new_func already initialized to
+ * g_log_default_handler above
+ */
+ } else {
+ new_func = gperl_log_func;
+ new_callback = gperl_log_callback_new
+ (log_func, user_data);
+ }
+ }
+
+ G_LOCK (gperl_log_default_handler_callback);
+
+ old_func = g_log_set_default_handler (new_func, new_callback);
+ old_callback = gperl_log_default_handler_callback;
+ gperl_log_default_handler_callback = new_callback;
+
+ G_UNLOCK (gperl_log_default_handler_callback);
+
+ RETVAL = &PL_sv_undef;
+ if (old_func == g_log_default_handler) {
+ CV *cv = get_cv ("Glib::Log::default_handler", 0);
+ assert (cv);
+ RETVAL = newRV_inc ((SV*) cv);
+ SvREFCNT_inc_simple_void_NN (RETVAL);
+ } else if (old_func == gperl_log_func) {
+ RETVAL = old_callback->func;
+ SvREFCNT_inc_simple_void_NN (RETVAL);
+ }
+ if (old_callback) {
+ gperl_callback_destroy (old_callback);
+ }
+ OUTPUT:
+ RETVAL
+
+#endif
# this is a little ugly, because i didn't want to export a typemap for
# GLogLevelFlags.
diff --git a/NEWS b/NEWS
index 7b5e000..e069f5c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
Overview of changes in the next unstable release of Glib
========================================================
+* Add Glib::Log->set_default_handler() and Glib::Log::default_handler().
* Add Glib::ParamSpec->override() and get_redirect_target().
* Add Glib::Param->get_default_value().
* Support the fundamental type Glib::GType.
diff --git a/t/a.t b/t/a.t
index 9e37dcb..792e60d 100644
--- a/t/a.t
+++ b/t/a.t
@@ -18,7 +18,7 @@ if ($Config{archname} =~ m/^(x86_64|mipsel|mips|alpha)/
# and in 2.4.0 (actually 2.3.2).
plan skip_all => "g_log doubles messages by accident on 64-bit platforms";
} else {
- plan tests => 12;
+ plan tests => 30;
}
package Foo;
@@ -66,6 +66,69 @@ SKIP: {
# i would expect this to call croak, but it actually just aborts. :-(
#eval { Glib->error (__PACKAGE__, 'error'); };
+Glib::Log::default_handler ('Test-Domain', ['info'], 'ignore this message');
+Glib::Log::default_handler ('Test-Domain', ['info'],
+ 'another message to ignore', 'userdata');
+
+SKIP: {
+ skip "new 2.6 stuff", 10
+ unless Glib->CHECK_VERSION (2,6,0);
+ Glib->log ('An-Unknown-Domain', ['info'], 'this is a test message');
+
+ is (Glib::Log->set_default_handler(undef),
+ \&Glib::Log::default_handler,
+ 'default log handler: install undef, prev default');
+ Glib->log ('An-Unknown-Domain', ['info'], 'this is a test message');
+
+ is (Glib::Log->set_default_handler(\&Glib::Log::default_handler),
+ \&Glib::Log::default_handler,
+ 'default log handler: install default, prev default');
+ Glib->log ('An-Unknown-Domain', ['info'], 'this is another test message');
+
+ # anon subs like $sub1 and $sub2 must refer to something like $x in the
+ # environment or they're not gc-ed immediately
+ my $x = 123;
+ my $sub1 = sub {
+ my @args = @_;
+ is (scalar @args, 3, 'sub1 arg count');
+ is ($args[0], 'An-Unknown-Domain', 'sub1 domain');
+ isa_ok ($args[1], 'Glib::LogLevelFlags', 'sub1 flags type');
+ ok ($args[1] == ['info'], 'sub1 flags value');
+ is ($args[2], 'a message', 'sub1 message');
+ return $x
+ };
+ is (Glib::Log->set_default_handler($sub1),
+ \&Glib::Log::default_handler,
+ 'default log handler: install sub1, prev default');
+ Glib->log ('An-Unknown-Domain', ['info'], 'a message');
+
+ my $sub2 = sub {
+ my @args = @_;
+ is (scalar @args, 4, 'sub2 arg count');
+ is ($args[0], 'Another-Unknown-Domain', 'sub2 domain');
+ isa_ok ($args[1], 'Glib::LogLevelFlags', 'sub2 flags type');
+ ok ($args[1] == ['warning'], 'sub2 flags value');
+ is ($args[2], 'a message', 'sub2 message');
+ is ($args[3], 'some userdata', 'sub2 userdata');
+ return $x
+ };
+ is (Glib::Log->set_default_handler($sub2,'some userdata'), $sub1,
+ 'default log handler: install sub2, prev sub1');
+ require Scalar::Util;
+ Scalar::Util::weaken ($sub1);
+ is ($sub1, undef,
+ 'sub1 garbage collected by weakening');
+ Glib->log ('Another-Unknown-Domain', ['warning'], 'a message');
+
+ is (Glib::Log->set_default_handler(undef), $sub2,
+ 'default log handler: install undef, prev sub2');
+ Glib->log ('Another-Unknown-Domain', ['info'], 'this is a test message');
+
+ is (Glib::Log->set_default_handler(undef),
+ \&Glib::Log::default_handler,
+ 'default log handler: install undef, prev default');
+ Glib->log ('Another-Unknown-Domain', ['info'], 'this is yet another a test message');
+}
# when you try to connect to a non-existant signal, you get a CRITICAL
@@ -106,7 +169,7 @@ Glib::Log->set_always_fatal ([qw/ info debug /]);
__END__
-Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the
+Copyright (C) 2003, 2009 by the gtk2-perl team (see the file AUTHORS for the
full list)
This library is free software; you can redistribute it and/or modify it under
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]