Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[platform-swt-dev] GTK2: warnings and criticals

We're currently just letting GTK warnings and criticals go to the
console. I've written a little code that intercepts warnings and
criticals (we could intercept other messages too, but these are the most
common ones triggered by misuse of GTK), and passes them back to a
static function in OS.java which could then trigger appropriate
exceptions (or just break in Java). This should make finding bugs in
GTK/SWT code much easier since you can trivially track down the call
that caused the warning.

I also have a code snippet along the same lines that causes warnings and
criticals to break in a C debugger (both this and the Java stuff can be
used in conjunction with one another). This allows you to attach gdb to
a process being run which will hit a breakpoint whenever GTK throws a
warning. Sometimes it is easier to figure out why a warning was being
thrown from the C side rather than the Java side.

Code isn't polished or finished, but it helps me out a lot so I hope
somebody else will find it useful too (and perhaps somebody will be
interested in doing the work to integrate it with eclipse so we get java
exceptions off the Gtk equivalent of exceptions).

-Seth
#include <signal.h>

static int stop_in_c_debugger_on_warning = 0;
static int call_swt_on_warning = 0;
static int log_handler_registered = 0;

static JNIEnv *warning_env = NULL;
static jclass warning_class;

static void
log_handler (const char *domain,
             GLogLevelFlags level,
             const char *message,
             gpointer data)
{
        /* this line prints the message, remove it to supress printing */
        g_log_default_handler (domain, level, message, data);

        /* you can filter for other messages using this if/then */
        if ((level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) != 0) {
	  if (stop_in_c_debugger_on_warning == -1) {
	    void (* saved_handler) (int);
	    /* through an interrupt signal which the debugger will catch
	     * it should be harmless if not running a debugger */
	    saved_handler = signal (SIGINT, SIG_IGN);
	    raise (SIGINT);
	    signal (SIGINT, saved_handler);
	  }

	  if (call_swt_on_warning == -1) {
	    jmethodID mid = (*warning_env)->GetStaticMethodID(warning_env, warning_class, "WarningCallback", "()V");
	    if (mid == NULL) return;
	    (*warning_env)->CallStaticVoidMethod(warning_env, warning_class, mid);
	  }
        }
}

static void
register_log_handler (JNIEnv *env, jclass that)
{
	guint i;

	static const char * const standard_log_domains[] = {
		"",
		"GConf",
		"GConf-Backends",
		"GLib",
		"GLib-GObject",
		"GModule",
		"GThread",
		"Gdk",
		"Gdk-Pixbuf",
		"GdkPixbuf",
		"Glib",
		"Gnome",
		"GnomeCanvas",
		"GnomePrint",
		"GnomeUI",
		"GnomeVFS",
		"GnomeVFS-pthread",
		"Gtk",
		"gnome-vfs-modules",
		"libgconf-scm",
		"libglade",
		"libgnomevfs",
	};

	if (log_handler_registered == -1) return;

	log_handler_registered = -1;

	warning_env = env;
	warning_class = that;

	for (i = 0; i < G_N_ELEMENTS (standard_log_domains); i++) {
		g_log_set_handler (standard_log_domains[i], G_LOG_LEVEL_MASK, log_handler, NULL);
	}
}

JNIEXPORT void JNICALL Java_org_eclipse_swt_internal_gtk_OS_make_1gtk_1warnings_1call_1OSdotWarningCallback
        (JNIEnv *env, jclass that)
{
        call_swt_on_warning = -1;
	register_log_handler(env, that);
}

JNIEXPORT void JNICALL Java_org_eclipse_swt_internal_gtk_OS_make_1gtk_1warnings_1stop_1in_1c_1debugger
	(JNIEnv *env, jclass that)
{
        stop_in_c_debugger_on_warning = -1;
        register_log_handler(env, that);
}

Back to the top