Re: [rfc][patch] Add optional PackageKit hook to install new applications



On Thu, 2008-12-04 at 17:29 +0000, Kenneth MacDonald wrote:
> On Thu, 2008-12-04 at 13:09 +0000, Richard Hughes wrote:
> 
> > Of course, an admin can switch off this functionality in
> > gnome-packagekit, or I can even add a nautilus GConf key to not even
> > show the question if you guys would prefer.
> > 
> > Comments appreciated.
> 
> Very cool, but we'd really want to be able to turn it off on e.g. lab
> machines so a GConf key would be ideal.

Version 3 attached for review.

Richard.

Index: configure.in
===================================================================
--- configure.in	(revision 14796)
+++ configure.in	(working copy)
@@ -65,6 +65,7 @@
 	gtk+-2.0		>= gtk_minver
 	libxml-2.0		>= xml_minver
 	unique-1.0
+	dbus-glib-1
 ])
 dnl ==========================================================================
 
@@ -317,6 +318,17 @@
 
 dnl ==========================================================================
 
+AC_ARG_ENABLE(packagekit, 
+	AC_HELP_STRING([--disable-packagekit], 
+			[build without PackageKit support]))
+msg_packagekit=no
+if test "x$enable_packagekit" != "xno"; then
+	msg_packagekit=yes
+	AC_DEFINE(ENABLE_PACKAGEKIT, 1, [define to enable PackageKit mimetype installer])
+fi
+
+dnl ==========================================================================
+
 dnl Turn on the additional warnings last, so -Werror doesn't affect other tests.
 
 AC_ARG_ENABLE(more-warnings,
@@ -473,6 +485,7 @@
 	tracker support:	$msg_tracker
 	beagle support:		$msg_beagle
 	xmp support:		$msg_xmp
+	PackageKit support:     $msg_packagekit
 
 	profiling support:      ${profiling_support}
 	nautilus-extension documentation: ${enable_gtk_doc}
Index: libnautilus-private/nautilus-mime-actions.c
===================================================================
--- libnautilus-private/nautilus-mime-actions.c	(revision 14796)
+++ libnautilus-private/nautilus-mime-actions.c	(working copy)
@@ -32,6 +32,11 @@
 #include <glib/gstdio.h>
 #include <string.h>
 
+#ifdef ENABLE_PACKAGEKIT
+ #include <dbus/dbus-glib.h>
+ #include <gdk/gdkx.h>
+#endif
+
 #include "nautilus-file-attributes.h"
 #include "nautilus-file.h"
 #include "nautilus-autorun.h"
@@ -73,6 +78,7 @@
 	gboolean tried_mounting;
 	char *activation_directory;
 	gboolean user_confirmation;
+	gboolean activate_retry;
 } ActivateParameters;
 
 /* Number of seconds until cancel dialog shows up */
@@ -1022,7 +1028,195 @@
 	return response == GTK_RESPONSE_YES;
 }
 
+#ifdef ENABLE_PACKAGEKIT
+
+/* prototype only required for ENABLE_PACKAGEKIT */
+static void activate_files (ActivateParameters *parameters);
+
 static void
+search_for_application_dbus_call_notify_cb (DBusGProxy *proxy, DBusGProxyCall *call, ActivateParameters *parameters)
+{
+	gboolean ret;
+	GError *error = NULL;
+
+	ret = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+	if (!ret) {
+		g_debug ("Did not install handler: %s", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* FIXME: activate the file again */
+	nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
+			    "need to activate file again");
+	activate_files (parameters);
+out:
+	return;
+}
+
+static void
+search_for_application_mime_type (ActivateParameters *parameters, const gchar *mime_type)
+{
+	DBusGConnection *connection;
+	DBusGProxy *proxy = NULL;
+	guint xid = 0;
+	GError *error = NULL;
+	DBusGProxyCall *call;
+	GtkWidget *dialog;
+	GdkWindow *window;
+
+	/* get bus */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL) {
+		g_warning ("Could not connect to session bus: %s\n", error->message);
+		g_error_free (error);
+		goto out;
+	}
+
+	/* get proxy - native clients for for KDE and GNOME */
+	proxy = dbus_g_proxy_new_for_name (connection,
+					   "org.freedesktop.PackageKit",
+					   "/org/freedesktop/PackageKit",
+					   "org.freedesktop.PackageKit");
+	if (proxy == NULL) {
+		g_warning ("Could not connect to PackageKit session service\n");
+		goto out;
+	}
+
+	/* get XID from parent window */
+	window = gtk_widget_get_window (GTK_WIDGET(parameters->parent_window));
+	if (window != NULL)
+		xid = GDK_WINDOW_XID (window);
+
+	/* don't timeout, as dbus-glib sets the timeout ~25 seconds */
+	dbus_g_proxy_set_default_timeout (proxy, INT_MAX);
+
+	/* invoke the method */
+	call = dbus_g_proxy_begin_call (proxy, "InstallMimeType",
+					(DBusGProxyCallNotify) search_for_application_dbus_call_notify_cb,
+					NULL, NULL,
+				        G_TYPE_UINT, xid,
+				        G_TYPE_UINT, 0,
+				        G_TYPE_STRING, mime_type,
+				        G_TYPE_INVALID);
+	if (call == NULL) {
+		g_warning ("Could not send method");
+		dialog = gtk_message_dialog_new (GTK_WINDOW (parameters->parent_window),
+						 GTK_DIALOG_MODAL,
+						 GTK_MESSAGE_ERROR,
+						 GTK_BUTTONS_OK,
+						 _("Could not use system package installer"));
+		g_signal_connect (G_OBJECT (dialog), "response",
+				  G_CALLBACK (gtk_widget_destroy), NULL);
+		gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+		gtk_widget_show (dialog);
+		goto out;
+	}
+
+	/* signal this, as we don't want to get stuck into a loop if
+	 * the application doesn't for some reason register the mime handler
+	 * it advertised
+	 */
+	parameters->activate_retry = TRUE;
+
+	nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER,
+			    "InstallMimeType method invoked for %s", mime_type);
+out:
+	if (proxy != NULL)
+		g_object_unref (proxy);
+}
+#endif
+
+static void
+application_unhandled_file (ActivateParameters *parameters, NautilusFile *file)
+{
+	GFile *location;
+	char *full_uri_for_display;
+	char *uri_for_display;
+	char *error_message;
+#ifdef ENABLE_PACKAGEKIT
+	char *secondary_text;
+	GtkWidget *dialog;
+	GtkButtonsType button;
+	gboolean show_install_mime;
+#endif
+	location = nautilus_file_get_location (file);
+	full_uri_for_display = g_file_get_parse_name (location);
+	g_object_unref (location);
+
+	/* Truncate the URI so it doesn't get insanely wide. Note that even
+	 * though the dialog uses wrapped text, if the URI doesn't contain
+	 * white space then the text-wrapping code is too stupid to wrap it.
+	 */
+	uri_for_display = eel_str_middle_truncate
+		(full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
+	g_free (full_uri_for_display);
+
+	error_message = g_strdup_printf (_("Could not display \"%s\"."),
+					 uri_for_display);
+	
+	g_free (uri_for_display);
+
+#ifndef ENABLE_PACKAGEKIT
+	/* show an unhelpful dialog */
+	eel_show_error_dialog (error_message,
+			       _("There is no application installed for this file type"),
+			       parameters->parent_window);
+	goto out;
+#else
+
+	/* we've installed something, that failed to register this mime type */
+	if (parameters->activate_retry) {
+		eel_show_error_dialog (error_message,
+				       _("The application installed could not open this file type"),
+				       parameters->parent_window);
+		goto out;
+	}
+
+	/* allow an admin to disable the PackageKit search functionality */
+	show_install_mime = eel_preferences_get_boolean (NAUTILUS_PREFERENCES_INSTALL_MIME_ACTIVATION);
+	if (!show_install_mime) {
+		eel_show_error_dialog (error_message,
+				       _("There is no application installed for this file type "
+				         "and application search has been disabled"),
+				       parameters->parent_window);
+		goto out;
+	}
+
+	/* pause the cancel dialog */
+	pause_activation_timed_cancel (parameters);
+
+	/* use a custom dialog to prompt the user to install new software */
+	dialog = gtk_message_dialog_new (GTK_WINDOW (parameters->parent_window),
+					 GTK_DIALOG_MODAL,
+					 GTK_MESSAGE_ERROR,
+					 GTK_BUTTONS_YES_NO,
+					 error_message);
+	secondary_text = g_strdup_printf ("%s\n%s",
+			    _("There is no application installed for this file type."),
+			    _("Do you want to search for an application to open this file?"));
+	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), secondary_text);
+	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+	button = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+
+	if (button == GTK_RESPONSE_YES) {
+		char *mime_type;
+		mime_type = nautilus_file_get_mime_type (file);
+		search_for_application_mime_type (parameters, mime_type);
+		g_free (mime_type);
+	}
+
+	g_free (secondary_text);
+
+	/* if we failed, use the cancel dialog */
+	unpause_activation_timed_cancel (parameters);
+#endif
+out:
+	g_free (error_message);
+}
+
+static void
 activate_files (ActivateParameters *parameters)
 {
 	NautilusWindowInfo *window_info;
@@ -1225,34 +1419,9 @@
 	}
 
 	for (l = unhandled_open_in_app_files; l != NULL; l = l->next) {
-		GFile *location;
-		char *full_uri_for_display;
-		char *uri_for_display;
-		char *error_message;
-		
 		file = NAUTILUS_FILE (l->data);
 
-		location = nautilus_file_get_location (file);
-		full_uri_for_display = g_file_get_parse_name (location);
-		g_object_unref (location);
-
-		/* Truncate the URI so it doesn't get insanely wide. Note that even
-		 * though the dialog uses wrapped text, if the URI doesn't contain
-		 * white space then the text-wrapping code is too stupid to wrap it.
-		 */
-		uri_for_display = eel_str_middle_truncate
-			(full_uri_for_display, MAX_URI_IN_DIALOG_LENGTH);
-		g_free (full_uri_for_display);
-	
-		error_message = g_strdup_printf (_("Could not display \"%s\"."),
-						 uri_for_display);
-		
-		g_free (uri_for_display);
-
-		eel_show_error_dialog (error_message,
-				       _("There is no application installed for this file type"),
-				       parameters->parent_window);
-		g_free (error_message);
+		application_unhandled_file (parameters, file);
 	}
 
 	window_info = NULL;
@@ -1630,6 +1799,7 @@
 	parameters->mode = mode;
 	parameters->flags = flags;
 	parameters->user_confirmation = user_confirmation;
+	parameters->activate_retry = FALSE;
 
 	file_count = g_list_length (files);
 	if (file_count == 1) {
Index: libnautilus-private/apps_nautilus_preferences.schemas.in
===================================================================
--- libnautilus-private/apps_nautilus_preferences.schemas.in	(revision 14796)
+++ libnautilus-private/apps_nautilus_preferences.schemas.in	(working copy)
@@ -301,6 +301,21 @@
     </schema>
 
     <schema>
+      <key>/schemas/apps/nautilus/preferences/install_mime_activation</key>
+      <applyto>/apps/nautilus/preferences/install_mime_activation</applyto>
+      <owner>nautilus</owner>
+      <type>bool</type>
+      <default>true</default>
+      <locale name="C">
+         <short>If to show the package installer for unknown mime types</short>
+         <long>
+        Whether to present the user a dialog to search using the package
+        installer for an application that can open an unknown mime type.
+         </long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/nautilus/preferences/theme</key>
       <applyto>/apps/nautilus/preferences/theme</applyto>
       <owner>nautilus</owner>
Index: libnautilus-private/nautilus-global-preferences.c
===================================================================
--- libnautilus-private/nautilus-global-preferences.c	(revision 14796)
+++ libnautilus-private/nautilus-global-preferences.c	(working copy)
@@ -278,6 +278,10 @@
 	  NULL, NULL,
 	  "executable_text_activation"
 	},
+	{ NAUTILUS_PREFERENCES_INSTALL_MIME_ACTIVATION,
+	  PREFERENCE_BOOLEAN,
+	  GINT_TO_POINTER (TRUE)
+	},
 	{ NAUTILUS_PREFERENCES_THEME,
 	  PREFERENCE_STRING,
 	  "default"
Index: libnautilus-private/nautilus-global-preferences.h
===================================================================
--- libnautilus-private/nautilus-global-preferences.h	(revision 14796)
+++ libnautilus-private/nautilus-global-preferences.h	(working copy)
@@ -93,6 +93,9 @@
 /* Activating executable text files */
 #define NAUTILUS_PREFERENCES_EXECUTABLE_TEXT_ACTIVATION		"preferences/executable_text_activation"
 
+/* Installing new packages when unknown mime type activated */
+#define NAUTILUS_PREFERENCES_INSTALL_MIME_ACTIVATION		"preferences/install_mime_activation"
+
 /* Spatial or browser mode */
 #define NAUTILUS_PREFERENCES_ALWAYS_USE_BROWSER       		"preferences/always_use_browser"
 #define NAUTILUS_PREFERENCES_ENABLE_TABS       			"preferences/tabs_enable"


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