PROPOSAL: revise GLib message system



hi all,

i'll start out with an overview of the current API:

typedef void            (*GErrorFunc)           (gchar    *str);
typedef void            (*GWarningFunc)         (gchar    *str);
typedef void            (*GPrintFunc)           (gchar    *str);

#define g_assert(expr)		       /* invoke g_error on failures */
#define g_assert_not_reached()	       /* invoke g_error */
#define g_return_if_fail(expr)         /* invoke g_warning on failures */
#define g_return_val_if_fail(expr,val) /* invoke g_warning on failures */

void g_error   (const gchar *format, ...) /* print error and abort */
void g_warning (const gchar *format, ...) /* print warning */
void g_message (const gchar *format, ...) /* print message */
void g_print   (const gchar *format, ...) /* print something */

/* override default handlers for the above functions */
GErrorFunc   g_set_error_handler   (GErrorFunc   func);
GWarningFunc g_set_warning_handler (GWarningFunc func);
GPrintFunc   g_set_message_handler (GPrintFunc func);
GPrintFunc   g_set_print_handler   (GPrintFunc func);


and a few message samples:

g_print ("Test Print\n");
> Test Print

g_message ("Test Message");
> message: Test Message

g_warning ("Test Warning");
> 
> ** WARNING **: Test Warning

g_error ("Test Error");
> 
> ** ERROR **: Test Error

now a few sample warnings that actually appear in gtk/gdk/glib:
  /* gtkmain.c: */ g_warning ("unable to register exit function");
  /* gdkimage.c: */ g_warning ("shmget failed!");
  /* gmem.c: */ g_warning ("trying to realloc freed memory\n");
gives:

> 
> ** WARNING **: unable to register exit function
> 
> ** WARNING **: shmget failed!
> 
> ** WARNING **: trying to realloc freed memory

i think it would be much nicer to get something like:

> 
> ** Gtk+-WARNING: unable to register exit function
> 
> ** Gdk-WARNING: shmget failed!
> 
> ** GLib-WARNING: trying to realloc freed memory

while g_warning ("Test Warning"); on the application level still produces:
>
> ** WARNING **: Test Warning

the same applies to g_message and g_error statements.
for things like the gimp, it doesn't actually make much sense to popup
a warning window if something below te gimp level is screwed.
imagine this warning window contains a GtkPixmap widget with a NULL
pixmap, this will cause a new warning window to popup and so on, until
the xserver crashes because of window overflow (i had that happening
some time ago, actually).
but unfortunately, with the current warning/error handlers, gimp can't
distinct between gtk, gdk, glib and gimp warnings.
further problems occour if gimp tries to handle messages/warnings that
come from e.g. gle. currently, parsing errors of ~/.glerc or the normal
g_return_if_fail () statements will be caught by the gimp's warning
handler, since i can't install custom handler functions for this without
reinventing the whole stuff for gle again.

to have warning, error and message handlers be implemented on a
per-library basis, i'd like to propose to rename
g_error to _g_error
g_warning to _g_warning
g_message to _g_message

and additionally have
void g_glib_error   (const gchar *format, ...);
void g_glib_warning (const gchar *format, ...);
void g_glib_message (const gchar *format, ...);
GErrorFunc   g_set_glib_error_handler   (GErrorFunc   func);
GWarningFunc g_set_glib_warning_handler (GWarningFunc func);
GPrintFunc   g_set_glib_message_handler (GPrintFunc func);

and then have this in glib.h:

#ifdef	GLIB_INTERNAL
#define	g_error		g_glib_error
#define	g_warning	g_glib_warning
#define	g_message	g_glib_message
#endif	/* GLIB_INTERNAL */

#ifndef	g_error
#define	g_error		_g_error
#endif	/* g_error */
#ifndef	g_warning
#define	g_warning	_g_warning
#endif	/* g_warning */
#ifndef	g_message
#define	g_message	_g_message
#endif	/* g_message */

if we then compile the glib *.c files with -DGLIB_INTERNAL, all the warnings
and errors from within glib will be routed through the g_glib_* functions,
while the current behaviour is still provided on the application level.
to get specialized warning, error and message handlers for gtk, we just need
to trade the
#include <gdk/gdk.h>
in the header files with something like
#include <gtk/gtkbase.h>
and have this in gtkbase.h:

#ifdef  GTK_INTERNAL
#define g_error         _gtk_error
#define g_warning       _gtk_warning
#define g_message       _gtk_message
#endif  /* GTK_INTERNAL */

#include <gdk/gdk.h>

/* the following functions should most probably go into gtkmain.h */
void _gtk_error   (const gchar *format, ...);
void _gtk_warning (const gchar *format, ...);
void _gtk_message (const gchar *format, ...);
GErrorFunc   gtk_set_error_handler   (GErrorFunc   func);
GWarningFunc gtk_set_warning_handler (GWarningFunc func);
GPrintFunc   gtk_set_message_handler (GPrintFunc func);

of course all gtk*.c files need to be compiled with -DGTK_INTERNAL.

the same scheme can be applied to gdk and -especially- gnome, which
introduces a bunch of different libraries. keep in mind, that nothing
will change on the application level with the new scheme, programmers
have just to explicitely overload the message handlers of underlying
libraries if they really intend to catch those as well.

on a related note, i think the current g_return_val_if_fail (1 == 2, 0);
> 
> ** WARNING **: file gwarn.c: line 6 (main): assertion "1 == 2" failed.
should better produce
> 
> ** WARNING **: file gwarn.c: line 6 (main): assertion failed: "1 == 2"

also, people should refrain from using g_print() inside of libraries and
better go for g_message() for informational purposes, since g_print()
is of actuall use on the application side to print into a special
purpose messaging window or something the like, which is not supposed
to contain debugging information of the underlying libraries.
since g_print() is usually used for debugging statements, it might be a
good idea to implement an additional g_debug() call, similar to the
current g_message() function.

g_debug() could even be combined with existing debug keys, such as
gdk_debug_flags, so code portions like

#ifdef G_ENABLE_DEBUG
  if (gdk_debug_flags & (GDK_DEBUG_EVENTS | GDK_DEBUG_DND))
    g_print ("GDK_DROP_LEAVE\n");
#endif

could be written as (inside gdk):

  g_debug (GDK_DEBUG_EVENTS | GDK_DEBUG_DND, "GDK_DROP_LEAVE");

and would produce:

> Gdk-Message: GDK_DROP_LEAVE


i'm curious to hear peoples comments on this isuue, and will most probably
go for the implementation of this in gtk, gdk and glib after a few days if
no one stands up and objects ;)

---
ciaoTJ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]