cpw.caseyho.crashreporter: c2c09c86: Adding ui to crash reporter

caseyho at pidgin.im caseyho at pidgin.im
Fri Feb 13 19:35:43 EST 2009


-----------------------------------------------------------------
Revision: c2c09c860ca7f350f99a4f0ce18b861e58750ee7
Ancestor: 3c453122d4b365fcabf2f55fe469db2ea8c66650
Author: caseyho at pidgin.im
Date: 2009-02-14T00:28:09
Branch: im.pidgin.cpw.caseyho.crashreporter
URL: http://d.pidgin.im/viewmtn/revision/info/c2c09c860ca7f350f99a4f0ce18b861e58750ee7

Modified files:
        pidgin/crash/Makefile.am pidgin/crash/crashreporter.c

ChangeLog: 

Adding ui to crash reporter

-------------- next part --------------
============================================================
--- pidgin/crash/Makefile.am	940da7d942fe28a6d365317d3f938e11ad180952
+++ pidgin/crash/Makefile.am	74e68d571e2896978185b5454849e18ed9c5bff1
@@ -4,7 +4,7 @@ pidgincrashreporter_SOURCES = \
 
 pidgincrashreporter_SOURCES = \
 	crashreporter.c \
-	minidump_stackwalk.cc
+	minidump_stackwalk.cc 
 
 pidgincrashreporter_LDADD = \
 	$(top_srcdir)/thirdparty/google-breakpad/src/libbreakpad.la \
============================================================
--- pidgin/crash/crashreporter.c	c4ffc4546ecf31851a17dd9d17d134d3ad3e5c35
+++ pidgin/crash/crashreporter.c	5ff40320754edadff69ebe16af0cbc1db865fd68
@@ -8,7 +8,11 @@
 #include <gtk/gtk.h>
 
 #include "core.h"
+#include "pidgin/gtkutils.h"
+#include "notify.h"
 
+static GtkWidget *window_;
+
 static PurpleCoreUiOps core_ops =
 {
 	NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
@@ -45,8 +49,268 @@ has_file_extension(const char *filename,
 }
 
 /**
- * Returns a hashtable mapping strings (library name) to PurplePlugin objects
+ * Makes a frame to display content in
+ * Derived from pidgin_make_frame
  */
+static GtkWidget *
+make_frame(GtkWidget *parent, const char *title)
+{
+	GtkWidget *vbox, *label, *hbox;
+	char *labeltitle;
+
+	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start(GTK_BOX(parent), vbox, FALSE, FALSE, 0);
+	gtk_widget_show(vbox);
+
+	label = gtk_label_new(NULL);
+
+	labeltitle = g_strdup_printf("<span weight=\"bold\">%s</span>", title);
+	gtk_label_set_markup(GTK_LABEL(label), labeltitle);
+	g_free(labeltitle);
+
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+	gtk_widget_show(hbox);
+
+	label = gtk_label_new("    ");
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	gtk_widget_show(label);
+
+	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
+	gtk_widget_show(vbox);
+
+	return vbox;
+}
+#ifndef _WIN32
+static gint
+uri_command(const char *command, gboolean sync)
+{
+	gchar *tmp;
+	GError *error = NULL;
+	gint ret = 0;
+
+	purple_debug_misc("gtknotify", "Executing %s\n", command);
+
+	if (!purple_program_is_valid(command))
+	{
+		tmp = g_strdup_printf(_("The browser command \"%s\" is invalid."),
+							  command ? command : "(none)");
+		purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp);
+		g_free(tmp);
+
+	}
+	else if (sync)
+	{
+		gint status;
+
+		if (!g_spawn_command_line_sync(command, NULL, NULL, &status, &error))
+		{
+			tmp = g_strdup_printf(_("Error launching \"%s\": %s"),
+										command, error->message);
+			purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp);
+			g_free(tmp);
+			g_error_free(error);
+		}
+		else
+			ret = status;
+	}
+	else
+	{
+		if (!g_spawn_command_line_async(command, &error))
+		{
+			tmp = g_strdup_printf(_("Error launching \"%s\": %s"),
+										command, error->message);
+			purple_notify_error(NULL, NULL, _("Unable to open URL"), tmp);
+			g_free(tmp);
+			g_error_free(error);
+		}
+	}
+
+	return ret;
+}
+#endif /* _WIN32 */
+
+/**
+ * Opens webpage in new browser window
+ * Derived from pidgin_notify_uri()
+ */
+static void *
+notify_uri(const char *uri)
+{
+#ifndef _WIN32
+	char *escaped = g_shell_quote(uri);
+	char *command = NULL;
+	char *remote_command = NULL;
+	const char *web_browser;
+	int place;
+
+	web_browser = purple_prefs_get_string(PIDGIN_PREFS_ROOT "/browsers/browser");
+	place = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/browsers/place");
+
+	/* if they are running gnome, use the gnome web browser */
+	if (purple_running_gnome() == TRUE)
+	{
+		char *tmp = g_find_program_in_path("xdg-open");
+		if (tmp == NULL)
+			command = g_strdup_printf("gnome-open %s", escaped);
+		else
+			command = g_strdup_printf("xdg-open %s", escaped);
+		g_free(tmp);
+	}
+	else if (purple_running_osx() == TRUE)
+	{
+		command = g_strdup_printf("open %s", escaped);
+	}
+	else if (!strcmp(web_browser, "epiphany") ||
+		!strcmp(web_browser, "galeon"))
+	{
+		if (place == PIDGIN_BROWSER_NEW_WINDOW)
+			command = g_strdup_printf("%s -w %s", web_browser, escaped);
+		else if (place == PIDGIN_BROWSER_NEW_TAB)
+			command = g_strdup_printf("%s -n %s", web_browser, escaped);
+		else
+			command = g_strdup_printf("%s %s", web_browser, escaped);
+	}
+	else if (!strcmp(web_browser, "xdg-open"))
+	{
+		command = g_strdup_printf("xdg-open %s", escaped);
+	}
+	else if (!strcmp(web_browser, "gnome-open"))
+	{
+		command = g_strdup_printf("gnome-open %s", escaped);
+	}
+	else if (!strcmp(web_browser, "kfmclient"))
+	{
+		command = g_strdup_printf("kfmclient openURL %s", escaped);
+		/*
+		 * Does Konqueror have options to open in new tab
+		 * and/or current window?
+		 */
+	}
+	else if (!strcmp(web_browser, "mozilla") ||
+			 !strcmp(web_browser, "mozilla-firebird") ||
+			 !strcmp(web_browser, "firefox") ||
+			 !strcmp(web_browser, "seamonkey"))
+	{
+		char *args = "";
+
+		command = g_strdup_printf("%s %s", web_browser, escaped);
+
+		/*
+		 * Firefox 0.9 and higher require a "-a firefox" option when
+		 * using -remote commands.  This breaks older versions of
+		 * mozilla.  So we include this other handly little string
+		 * when calling firefox.  If the API for remote calls changes
+		 * any more in firefox then firefox should probably be split
+		 * apart from mozilla-firebird and mozilla... but this is good
+		 * for now.
+		 */
+		if (!strcmp(web_browser, "firefox"))
+			args = "-a firefox";
+
+		if (place == PIDGIN_BROWSER_NEW_WINDOW)
+			remote_command = g_strdup_printf("%s %s -remote "
+											 "openURL(%s,new-window)",
+											 web_browser, args, escaped);
+		else if (place == PIDGIN_BROWSER_NEW_TAB)
+			remote_command = g_strdup_printf("%s %s -remote "
+											 "openURL(%s,new-tab)",
+											 web_browser, args, escaped);
+		else if (place == PIDGIN_BROWSER_CURRENT)
+			remote_command = g_strdup_printf("%s %s -remote "
+											 "openURL(%s)",
+											 web_browser, args, escaped);
+	}
+	else if (!strcmp(web_browser, "netscape"))
+	{
+		command = g_strdup_printf("netscape %s", escaped);
+
+		if (place == PIDGIN_BROWSER_NEW_WINDOW)
+		{
+			remote_command = g_strdup_printf("netscape -remote "
+											 "openURL(%s,new-window)",
+											 escaped);
+		}
+		else if (place == PIDGIN_BROWSER_CURRENT)
+		{
+			remote_command = g_strdup_printf("netscape -remote "
+											 "openURL(%s)", escaped);
+		}
+	}
+	else if (!strcmp(web_browser, "opera"))
+	{
+		if (place == PIDGIN_BROWSER_NEW_WINDOW)
+			command = g_strdup_printf("opera -newwindow %s", escaped);
+		else if (place == PIDGIN_BROWSER_NEW_TAB)
+			command = g_strdup_printf("opera -newpage %s", escaped);
+		else if (place == PIDGIN_BROWSER_CURRENT)
+		{
+			remote_command = g_strdup_printf("opera -remote "
+											 "openURL(%s)", escaped);
+			command = g_strdup_printf("opera %s", escaped);
+		}
+		else
+			command = g_strdup_printf("opera %s", escaped);
+
+	}
+	else if (!strcmp(web_browser, "custom"))
+	{
+		const char *web_command;
+
+		web_command = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/browsers/command");
+
+		if (web_command == NULL || *web_command == '\0')
+		{
+			purple_notify_error(NULL, NULL, _("Unable to open URL"),
+							  _("The 'Manual' browser command has been "
+								"chosen, but no command has been set."));
+			return NULL;
+		}
+
+		if (strstr(web_command, "%s"))
+			command = purple_strreplace(web_command, "%s", escaped);
+		else
+		{
+			/*
+			 * There is no "%s" in the browser command.  Assume the user
+			 * wanted the URL tacked on to the end of the command.
+			 */
+			command = g_strdup_printf("%s %s", web_command, escaped);
+		}
+	}
+
+	g_free(escaped);
+
+	if (remote_command != NULL)
+	{
+		/* try the remote command first */
+		if (uri_command(remote_command, TRUE) != 0)
+			uri_command(command, FALSE);
+
+		g_free(remote_command);
+
+	}
+	else
+		uri_command(command, FALSE);
+
+	g_free(command);
+
+#else /* !_WIN32 */
+	winpidgin_notify_uri(uri);
+#endif /* !_WIN32 */
+
+	return NULL;
+}
+
+/**
+ * Returns a hashtable mapping strings (library name) to PurplePlugin objects.
+ * Derived from purple_probe_plugins()
+ */
 static GHashTable*
 probe_plugins () 
 {
@@ -94,6 +358,171 @@ probe_plugins () 
 	return plugins;
 }
 
+static void 
+crash_info_closed (GtkWidget *widget, gpointer data)
+{
+	gtk_main_quit ();
+}
+
+static void
+close_window (GtkWidget *widget, gpointer data)
+{
+	gtk_main_quit ();
+}
+
+static void
+report_bug (GtkWidget *widget, gpointer data)
+{
+	gchar *website = (gchar *) data;
+	notify_uri(website);
+}
+
+static void
+process_crash_info (const char *minidump_file, GHashTable *plugins)
+{
+	GtkWidget *label, *vbox, *hbox, *frame, *logo, *button;
+	GdkPixbuf *pixbuf;
+	AtkObject *obj;
+	gchar *text, *tmp, *filename;
+	gchar *crash_module_name;
+	GList *module_names, *iter;
+
+	module_names = pidgin_crash_module_stack(minidump_file);
+
+	crash_module_name = (gchar *)module_names->data;
+	purple_debug_info("crash", 
+		"crashed module name is %s\n", crash_module_name);
+
+	PurplePlugin *crashed_plugin = 
+		g_hash_table_lookup(plugins, crash_module_name);
+
+	/* Construct the display */
+	window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title(GTK_WINDOW (window_), _("Pidgin Crash Reporter"));
+	gtk_window_set_default_size(GTK_WINDOW(window_), 500, 200);
+	gtk_container_set_border_width(GTK_CONTAINER(window_), 10);
+
+	g_signal_connect(
+		G_OBJECT(window_), "destroy", 
+		G_CALLBACK(crash_info_closed), NULL);
+	gtk_widget_show_all(window_);
+
+	vbox = gtk_vbox_new (FALSE, PIDGIN_HIG_BOX_SPACE);
+	gtk_container_add (GTK_CONTAINER(window_), vbox);
+
+	/* Insert Pidgin logo (copied from about dialog)
+	 * TODO: This might be superfluous...is this a good idea?
+	 */
+	/* Generate a logo with a version number */
+	logo = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_widget_realize(logo);
+	filename = g_build_filename(DATADIR, "pixmaps", "pidgin", "logo.png", NULL);
+	pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+	g_free(filename);
+#if 0  /* Don't versionize the logo when the logo has the version in it */
+	pidgin_logo_versionize(&pixbuf, logo);
+#endif
+	gtk_widget_destroy(logo);
+	logo = gtk_image_new_from_pixbuf(pixbuf);
+	gdk_pixbuf_unref(pixbuf);
+	/* Insert the logo */
+	obj = gtk_widget_get_accessible(logo);
+	tmp = g_strconcat(PIDGIN_NAME, " " DISPLAY_VERSION, NULL);
+	atk_object_set_description(obj, tmp);
+	g_free(tmp);
+	gtk_box_pack_start(GTK_BOX(vbox), logo, FALSE, FALSE, 0);
+
+
+	/* Display intro text */
+	/*
+	frame = make_frame(vbox, _("Pidgin has crashed"));
+	label = gtk_label_new(_("Crash data has been saved (see below)."));
+	gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+	*/
+
+	/* Display crashed plugin info */
+	if (crashed_plugin && crashed_plugin->info->name) {
+		purple_debug_info("crash", 
+			"found plugin corresponding to crash\n");
+
+		frame = make_frame(vbox, _("Source"));
+		label = gtk_label_new (crashed_plugin->info->name);	
+		gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+		if (crashed_plugin->info->homepage) {
+			text = g_strdup_printf("Report bugs at %s",
+				crashed_plugin->info->homepage);
+			label = gtk_label_new(text);
+			gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+			g_free(text);
+			gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+		}
+	} else {
+		purple_debug_info("crash", 
+			"did not find plugin corresponding to crash\n");
+	}
+
+	/* Module name */
+	frame = make_frame(vbox, _("Crashed modules"));
+
+	text = g_strdup_printf("%s (crashed)", crash_module_name);
+	label = gtk_label_new(text);
+	gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+	g_free(text);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+	text = strdup ("");
+	int i = 0;
+	for (iter = module_names; iter != NULL; iter = iter->next) {
+		tmp = g_strdup_printf("%s%d %s\; ",
+			text, i, (gchar *)iter->data); 
+		g_free(text);
+		text = tmp;
+		i++;
+	}
+
+	label = gtk_label_new(text);
+	gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+	g_free(text);
+	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
+
+	/* Minidump location */
+	frame = make_frame(vbox, _("Crash data"));
+	label = gtk_label_new (minidump_file);
+	gtk_box_pack_start(frame, label, FALSE, FALSE, 0);
+
+	/* Close button */
+	hbox = gtk_hbox_new(TRUE, PIDGIN_HIG_BOX_SPACE);
+	gtk_box_pack_start(vbox, hbox, FALSE, FALSE, 0);
+
+	button = gtk_button_new_from_stock(GTK_STOCK_HELP);
+	gtk_box_pack_start(hbox, button, TRUE, TRUE, 0);
+
+	text = (crashed_plugin && crashed_plugin->info->homepage) ?
+		crashed_plugin->info->homepage :
+		PURPLE_WEBSITE;
+
+	g_signal_connect(G_OBJECT(button), "clicked",
+		G_CALLBACK(report_bug),
+		text);
+
+	button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+	gtk_box_pack_start(hbox, button, TRUE, TRUE, 0);
+	g_signal_connect(G_OBJECT(button), "clicked",
+		G_CALLBACK(close_window), NULL);
+
+	/* Show it */
+	gtk_widget_show_all(vbox);
+
+	/* Cleanup */
+	while(module_names != NULL) {
+		g_free(module_names->data);
+		module_names = module_names->next;
+	}
+}
+
+
 int main (int argc, char **argv) {
 	char *search_path;
 	GHashTable *plugins;
@@ -153,15 +582,11 @@ int main (int argc, char **argv) {
 	const char *minidump_file = argv[1];
 	purple_debug_info("crash", "minidump file name is %s\n", minidump_file);
 
-	GList *module_names = pidgin_crash_module_stack(minidump_file);
+	process_crash_info(minidump_file, plugins);
 
+	/* Start the main loop */
+	gtk_main ();
 
-
-	while(module_names != NULL) {
-		g_free(module_names->data);
-		module_names = module_names->next;
-	}
-
 	return 0;
 }
 


More information about the Commits mailing list