summaryrefslogtreecommitdiff
path: root/drivemount/drive-button.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivemount/drive-button.c')
-rw-r--r--drivemount/drive-button.c916
1 files changed, 916 insertions, 0 deletions
diff --git a/drivemount/drive-button.c b/drivemount/drive-button.c
new file mode 100644
index 00000000..e34b368d
--- /dev/null
+++ b/drivemount/drive-button.c
@@ -0,0 +1,916 @@
+/* -*- mode: C; c-basic-offset: 4 -*-
+ * Drive Mount Applet
+ * Copyright (c) 2004 Canonical Ltd
+ * Copyright 2008 Pierre Ossman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author:
+ * James Henstridge <[email protected]>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gio/gio.h>
+#include "drive-button.h"
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <mateconf/mateconf-client.h>
+
+#include <string.h>
+
+enum {
+ CMD_NONE,
+ CMD_MOUNT_OR_PLAY,
+ CMD_UNMOUNT,
+ CMD_EJECT
+};
+
+#define MATECONF_ROOT_AUTOPLAY "/desktop/mate/volume_manager/"
+
+/* type registration boilerplate code */
+G_DEFINE_TYPE(DriveButton, drive_button, GTK_TYPE_BUTTON)
+
+static void drive_button_set_volume (DriveButton *self,
+ GVolume *volume);
+static void drive_button_set_mount (DriveButton *self,
+ GMount *mount);
+static void drive_button_reset_popup (DriveButton *self);
+static void drive_button_ensure_popup (DriveButton *self);
+
+static void drive_button_destroy (GtkObject *object);
+#if 0
+static void drive_button_unrealize (GtkWidget *widget);
+#endif /* 0 */
+static gboolean drive_button_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static gboolean drive_button_key_press (GtkWidget *widget,
+ GdkEventKey *event);
+static void drive_button_theme_change (GtkIconTheme *icon_theme,
+ gpointer data);
+
+static void
+drive_button_class_init (DriveButtonClass *class)
+{
+ GTK_OBJECT_CLASS(class)->destroy = drive_button_destroy;
+ GTK_WIDGET_CLASS(class)->button_press_event = drive_button_button_press;
+ GTK_WIDGET_CLASS(class)->key_press_event = drive_button_key_press;
+
+ gtk_rc_parse_string ("\n"
+ " style \"drive-button-style\"\n"
+ " {\n"
+ " GtkWidget::focus-line-width=0\n"
+ " GtkWidget::focus-padding=0\n"
+ " bg_pixmap[NORMAL] = \"<parent>\"\n"
+ " bg_pixmap[ACTIVE] = \"<parent>\"\n"
+ " bg_pixmap[PRELIGHT] = \"<parent>\"\n"
+ " bg_pixmap[INSENSITIVE] = \"<parent>\"\n"
+ " }\n"
+ "\n"
+ " class \"DriveButton\" style \"drive-button-style\"\n"
+ "\n");
+}
+
+static void
+drive_button_init (DriveButton *self)
+{
+ GtkWidget *image;
+
+ image = gtk_image_new ();
+ gtk_container_add (GTK_CONTAINER (self), image);
+ gtk_widget_show(image);
+
+ self->volume = NULL;
+ self->mount = NULL;
+ self->icon_size = 24;
+ self->update_tag = 0;
+
+ self->popup_menu = NULL;
+}
+
+GtkWidget *
+drive_button_new (GVolume *volume)
+{
+ DriveButton *self;
+
+ self = g_object_new (DRIVE_TYPE_BUTTON, NULL);
+ drive_button_set_volume (self, volume);
+
+ g_signal_connect (gtk_icon_theme_get_default (),
+ "changed", G_CALLBACK (drive_button_theme_change),
+ self);
+
+ return (GtkWidget *)self;
+}
+
+GtkWidget *
+drive_button_new_from_mount (GMount *mount)
+{
+ DriveButton *self;
+
+ self = g_object_new (DRIVE_TYPE_BUTTON, NULL);
+ drive_button_set_mount (self, mount);
+
+ g_signal_connect (gtk_icon_theme_get_default (),
+ "changed", G_CALLBACK (drive_button_theme_change),
+ self);
+
+ return (GtkWidget *)self;
+}
+
+static void
+drive_button_destroy (GtkObject *object)
+{
+ DriveButton *self = DRIVE_BUTTON (object);
+
+ drive_button_set_volume (self, NULL);
+
+ if (self->update_tag)
+ g_source_remove (self->update_tag);
+ self->update_tag = 0;
+
+ drive_button_reset_popup (self);
+
+ if (GTK_OBJECT_CLASS (drive_button_parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (drive_button_parent_class)->destroy) (object);
+}
+
+#if 0
+static void
+drive_button_unrealize (GtkWidget *widget)
+{
+ DriveButton *self = DRIVE_BUTTON (widget);
+
+ drive_button_reset_popup (self);
+
+ if (GTK_WIDGET_CLASS (drive_button_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (drive_button_parent_class)->unrealize) (widget);
+}
+#endif /* 0 */
+
+/* the following function is adapted from gtkmenuitem.c */
+static void
+position_menu (GtkMenu *menu, gint *x, gint *y,
+ gboolean *push_in, gpointer user_data)
+{
+ GtkWidget *widget = GTK_WIDGET (user_data);
+ GdkScreen *screen;
+ gint twidth, theight, tx, ty;
+ GtkAllocation allocation;
+ GtkRequisition requisition;
+ GtkTextDirection direction;
+ GdkRectangle monitor;
+ gint monitor_num;
+
+ g_return_if_fail (menu != NULL);
+ g_return_if_fail (x != NULL);
+ g_return_if_fail (y != NULL);
+
+ if (push_in) *push_in = FALSE;
+
+ direction = gtk_widget_get_direction (widget);
+
+ gtk_widget_get_requisition (GTK_WIDGET (menu), &requisition);
+ twidth = requisition.width;
+ theight = requisition.height;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (widget));
+ if (monitor_num < 0) monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ if (!gdk_window_get_origin (gtk_widget_get_window (widget), &tx, &ty)) {
+ g_warning ("Menu not on screen");
+ return;
+ }
+
+ gtk_widget_get_allocation (widget, &allocation);
+ tx += allocation.x;
+ ty += allocation.y;
+
+ if (direction == GTK_TEXT_DIR_RTL)
+ tx += allocation.width - twidth;
+
+ if ((ty + allocation.height + theight) <= monitor.y + monitor.height)
+ ty += allocation.height;
+ else if ((ty - theight) >= monitor.y)
+ ty -= theight;
+ else if (monitor.y + monitor.height - (ty + allocation.height) > ty)
+ ty += allocation.height;
+ else
+ ty -= theight;
+
+ *x = CLAMP (tx, monitor.x, MAX (monitor.x, monitor.x + monitor.width - twidth));
+ *y = ty;
+ gtk_menu_set_monitor (menu, monitor_num);
+}
+
+static gboolean
+drive_button_button_press (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ DriveButton *self = DRIVE_BUTTON (widget);
+
+ /* don't consume non-button1 presses */
+ if (event->button == 1) {
+ drive_button_ensure_popup (self);
+ if (self->popup_menu) {
+ gtk_menu_popup (GTK_MENU (self->popup_menu), NULL, NULL,
+ position_menu, self,
+ event->button, event->time);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+drive_button_key_press (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ DriveButton *self = DRIVE_BUTTON (widget);
+
+ switch (event->keyval) {
+ case GDK_KP_Space:
+ case GDK_space:
+ case GDK_KP_Enter:
+ case GDK_Return:
+ drive_button_ensure_popup (self);
+ if (self->popup_menu) {
+ gtk_menu_popup (GTK_MENU (self->popup_menu), NULL, NULL,
+ position_menu, self,
+ 0, event->time);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+drive_button_theme_change (GtkIconTheme *icon_theme, gpointer data)
+{
+ drive_button_queue_update (data);
+}
+
+static void
+drive_button_set_volume (DriveButton *self, GVolume *volume)
+{
+ g_return_if_fail (DRIVE_IS_BUTTON (self));
+
+ if (self->volume) {
+ g_object_unref (self->volume);
+ }
+ self->volume = NULL;
+ if (self->mount) {
+ g_object_unref (self->mount);
+ }
+ self->mount = NULL;
+
+ if (volume) {
+ self->volume = g_object_ref (volume);
+ }
+ drive_button_queue_update (self);
+}
+
+static void
+drive_button_set_mount (DriveButton *self, GMount *mount)
+{
+ g_return_if_fail (DRIVE_IS_BUTTON (self));
+
+ if (self->volume) {
+ g_object_unref (self->volume);
+ }
+ self->volume = NULL;
+ if (self->mount) {
+ g_object_unref (self->mount);
+ }
+ self->mount = NULL;
+
+ if (mount) {
+ self->mount = g_object_ref (mount);
+ }
+ drive_button_queue_update (self);
+}
+
+static gboolean
+drive_button_update (gpointer user_data)
+{
+ DriveButton *self;
+ GdkScreen *screen;
+ GtkIconTheme *icon_theme;
+ GtkIconInfo *icon_info;
+ GIcon *icon;
+ int width, height;
+ GdkPixbuf *pixbuf = NULL, *scaled;
+ GtkRequisition button_req, image_req;
+ char *display_name, *tip;
+
+ g_return_val_if_fail (DRIVE_IS_BUTTON (user_data), FALSE);
+ self = DRIVE_BUTTON (user_data);
+ self->update_tag = 0;
+
+ drive_button_reset_popup (self);
+
+ /* if no volume or mount, unset image */
+ if (!self->volume && !self->mount) {
+ if (gtk_bin_get_child (GTK_BIN (self)) != NULL)
+ gtk_image_set_from_pixbuf (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (self))), NULL);
+ return FALSE;
+ }
+
+ if (self->volume) {
+ GMount *mount;
+
+ display_name = g_volume_get_name (self->volume);
+ mount = g_volume_get_mount (self->volume);
+
+ if (mount)
+ tip = g_strdup_printf ("%s\n%s", display_name, _("(mounted)"));
+ else
+ tip = g_strdup_printf ("%s\n%s", display_name, _("(not mounted)"));
+
+ if (mount)
+ icon = g_mount_get_icon (mount);
+ else
+ icon = g_volume_get_icon (self->volume);
+
+ if (mount)
+ g_object_unref (mount);
+ } else {
+ display_name = g_mount_get_name (self->mount);
+ tip = g_strdup_printf ("%s\n%s", display_name, _("(mounted)"));
+ icon = g_mount_get_icon (self->mount);
+ }
+
+ gtk_widget_set_tooltip_text (GTK_WIDGET (self), tip);
+ g_free (tip);
+ g_free (display_name);
+
+ /* base the icon size on the desired button size */
+ gtk_widget_size_request (GTK_WIDGET (self), &button_req);
+ gtk_widget_size_request (gtk_bin_get_child (GTK_BIN (self)), &image_req);
+ width = self->icon_size - (button_req.width - image_req.width);
+ height = self->icon_size - (button_req.height - image_req.height);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (self));
+ icon_theme = gtk_icon_theme_get_for_screen (screen);
+ icon_info = gtk_icon_theme_lookup_by_gicon (icon_theme, icon,
+ MIN (width, height),
+ GTK_ICON_LOOKUP_USE_BUILTIN);
+ if (icon_info)
+ {
+ pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
+ gtk_icon_info_free (icon_info);
+ }
+
+ g_object_unref (icon);
+
+ if (!pixbuf)
+ return FALSE;
+
+ scaled = gdk_pixbuf_scale_simple (pixbuf, width, height, GDK_INTERP_BILINEAR);
+ if (scaled) {
+ g_object_unref (pixbuf);
+ pixbuf = scaled;
+ }
+
+ gtk_image_set_from_pixbuf (GTK_IMAGE (gtk_bin_get_child (GTK_BIN (self))), pixbuf);
+ g_object_unref (pixbuf);
+
+ gtk_widget_size_request (GTK_WIDGET (self), &button_req);
+
+ return FALSE;
+}
+
+void
+drive_button_queue_update (DriveButton *self)
+{
+ if (!self->update_tag) {
+ self->update_tag = g_idle_add (drive_button_update, self);
+ }
+}
+
+void
+drive_button_set_size (DriveButton *self, int icon_size)
+{
+ g_return_if_fail (DRIVE_IS_BUTTON (self));
+
+ if (self->icon_size != icon_size) {
+ self->icon_size = icon_size;
+ drive_button_queue_update (self);
+ }
+}
+
+int
+drive_button_compare (DriveButton *button, DriveButton *other_button)
+{
+ /* sort drives before driveless volumes volumes */
+ if (button->volume) {
+ if (other_button->volume)
+ {
+ int cmp;
+ gchar *str1, *str2;
+
+ str1 = g_volume_get_name (button->volume);
+ str2 = g_volume_get_name (other_button->volume);
+ cmp = g_utf8_collate (str1, str2);
+ g_free (str2);
+ g_free (str1);
+
+ return cmp;
+ } else {
+ return -1;
+ }
+ } else {
+ if (other_button->volume)
+ {
+ return 1;
+ } else {
+ int cmp;
+ gchar *str1, *str2;
+
+ str1 = g_mount_get_name (button->mount);
+ str2 = g_mount_get_name (other_button->mount);
+ cmp = g_utf8_collate (str1, str2);
+ g_free (str2);
+ g_free (str1);
+
+ return cmp;
+ }
+ }
+}
+
+static void
+drive_button_reset_popup (DriveButton *self)
+{
+ if (self->popup_menu)
+ gtk_object_destroy (GTK_OBJECT (self->popup_menu));
+ self->popup_menu = NULL;
+}
+
+#if 0
+static void
+popup_menu_detach (GtkWidget *attach_widget, GtkMenu *menu)
+{
+ DRIVE_BUTTON (attach_widget)->popup_menu = NULL;
+}
+#endif /* 0 */
+
+static char *
+escape_underscores (const char *str)
+{
+ char *new_str;
+ int i, j, count;
+
+ /* count up how many underscores are in the string */
+ count = 0;
+ for (i = 0; str[i] != '\0'; i++) {
+ if (str[i] == '_')
+ count++;
+ }
+ /* copy to new string, doubling up underscores */
+ new_str = g_new (char, i + count + 1);
+ for (i = j = 0; str[i] != '\0'; i++, j++) {
+ new_str[j] = str[i];
+ if (str[i] == '_')
+ new_str[++j] = '_';
+ }
+ new_str[j] = '\0';
+ return new_str;
+}
+static GtkWidget *
+create_menu_item (DriveButton *self, const gchar *icon_name,
+ const gchar *label, GCallback callback,
+ gboolean sensitive)
+{
+ GtkWidget *item, *image;
+
+ item = gtk_image_menu_item_new_with_mnemonic (label);
+ if (icon_name) {
+ image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), image);
+ gtk_widget_show (image);
+ }
+ if (callback)
+ g_signal_connect_object (item, "activate", callback, self,
+ G_CONNECT_SWAPPED);
+ gtk_widget_set_sensitive (item, sensitive);
+ gtk_widget_show (item);
+ return item;
+}
+
+static void
+open_drive (DriveButton *self, GtkWidget *item)
+{
+ GdkScreen *screen;
+ GtkWidget *dialog;
+ GError *error = NULL;
+ char *argv[3] = { "caja", NULL, NULL };
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (self));
+
+ if (self->volume) {
+ GMount *mount;
+
+ mount = g_volume_get_mount (self->volume);
+ if (mount) {
+ GFile *file;
+
+ file = g_mount_get_root (mount);
+
+ argv[1] = g_file_get_uri (file);
+ g_object_unref(file);
+
+ g_object_unref(mount);
+ }
+ } else if (self->mount) {
+ GFile *file;
+
+ file = g_mount_get_root (self->mount);
+ argv[1] = g_file_get_uri (file);
+ g_object_unref(file);
+ } else
+ g_return_if_reached();
+
+ if (!gdk_spawn_on_screen (screen, NULL, argv, NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL, NULL, NULL, &error)) {
+ dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot execute '%s'"),
+ argv[0]);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), error->message, NULL);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_object_destroy), NULL);
+ gtk_widget_show (dialog);
+ g_error_free (error);
+ }
+ g_free (argv[1]);
+}
+
+/* copied from mate-volume-manager/src/manager.c maybe there is a better way than
+ * duplicating this code? */
+
+/*
+ * gvm_run_command - run the given command, replacing %d with the device node
+ * and %m with the given path
+ */
+static void
+gvm_run_command (const char *device, const char *command, const char *path)
+{
+ char *argv[4];
+ gchar *new_command;
+ GError *error = NULL;
+ GString *exec = g_string_new (NULL);
+ char *p, *q;
+
+ /* perform s/%d/device/ and s/%m/path/ */
+ new_command = g_strdup (command);
+ q = new_command;
+ p = new_command;
+ while ((p = strchr (p, '%')) != NULL) {
+ if (*(p + 1) == 'd') {
+ *p = '\0';
+ g_string_append (exec, q);
+ g_string_append (exec, device);
+ q = p + 2;
+ p = p + 2;
+ } else if (*(p + 1) == 'm') {
+ *p = '\0';
+ g_string_append (exec, q);
+ g_string_append (exec, path);
+ q = p + 2;
+ p = p + 2;
+ } else {
+ /* Ignore anything else. */
+ p++;
+ }
+ }
+ g_string_append (exec, q);
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = exec->str;
+ argv[3] = NULL;
+
+ g_spawn_async (g_get_home_dir (), argv, NULL, 0, NULL, NULL,
+ NULL, &error);
+ if (error) {
+ g_warning ("failed to exec %s: %s\n", exec->str, error->message);
+ g_error_free (error);
+ }
+
+ g_string_free (exec, TRUE);
+ g_free (new_command);
+}
+
+/*
+ * gvm_check_dvd_only - is this a Video DVD?
+ *
+ * Returns TRUE if this was a Video DVD and FALSE otherwise.
+ * (the original in gvm was also running the autoplay action,
+ * I removed that code, so I renamed from gvm_check_dvd to
+ * gvm_check_dvd_only)
+ */
+static gboolean
+gvm_check_dvd_only (const char *udi, const char *device, const char *mount_point)
+{
+ char *path;
+ gboolean retval;
+
+ path = g_build_path (G_DIR_SEPARATOR_S, mount_point, "video_ts", NULL);
+ retval = g_file_test (path, G_FILE_TEST_IS_DIR);
+ g_free (path);
+
+ /* try the other name, if needed */
+ if (retval == FALSE) {
+ path = g_build_path (G_DIR_SEPARATOR_S, mount_point,
+ "VIDEO_TS", NULL);
+ retval = g_file_test (path, G_FILE_TEST_IS_DIR);
+ g_free (path);
+ }
+
+ return retval;
+}
+/* END copied from mate-volume-manager/src/manager.c */
+
+static gboolean
+check_dvd_video (DriveButton *self)
+{
+ GFile *file;
+ char *udi, *device_path, *mount_path;
+ gboolean result;
+ GMount *mount;
+
+ if (!self->volume)
+ return FALSE;
+
+ mount = g_volume_get_mount (self->volume);
+ if (!mount)
+ return FALSE;
+
+ file = g_mount_get_root (mount);
+ g_object_unref (mount);
+
+ if (!file)
+ return FALSE;
+
+ mount_path = g_file_get_path (file);
+
+ g_object_unref (file);
+
+ device_path = g_volume_get_identifier (self->volume,
+ G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
+ udi = g_volume_get_identifier (self->volume,
+ G_VOLUME_IDENTIFIER_KIND_HAL_UDI);
+
+ result = gvm_check_dvd_only (udi, device_path, mount_path);
+
+ g_free (device_path);
+ g_free (udi);
+ g_free (mount_path);
+
+ return result;
+}
+
+static gboolean
+check_audio_cd (DriveButton *self)
+{
+ GFile *file;
+ char *activation_uri;
+ GMount *mount;
+
+ if (!self->volume)
+ return FALSE;
+
+ mount = g_volume_get_mount (self->volume);
+ if (!mount)
+ return FALSE;
+
+ file = g_mount_get_root (mount);
+ g_object_unref (mount);
+
+ if (!file)
+ return FALSE;
+
+ activation_uri = g_file_get_uri (file);
+
+ g_object_unref (file);
+
+ /* we have an audioCD if the activation URI starts by 'cdda://' */
+ gboolean result = (strncmp ("cdda://", activation_uri, 7) == 0);
+ g_free (activation_uri);
+ return result;
+}
+
+static void
+run_command (DriveButton *self, const char *command)
+{
+ GFile *file;
+ char *mount_path, *device_path;
+ GMount *mount;
+
+ if (!self->volume)
+ return;
+
+ mount = g_volume_get_mount (self->volume);
+ if (!mount)
+ return;
+
+ file = g_mount_get_root (mount);
+ g_object_unref (mount);
+
+ g_assert (file);
+
+ mount_path = g_file_get_path (file);
+
+ g_object_unref (file);
+
+ device_path = g_volume_get_identifier (self->volume,
+ G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
+
+ gvm_run_command (device_path, command, mount_path);
+
+ g_free (mount_path);
+ g_free (device_path);
+}
+
+static void
+mount_drive (DriveButton *self, GtkWidget *item)
+{
+ if (self->volume) {
+ GMountOperation *mount_op = gtk_mount_operation_new (NULL);
+ g_volume_mount (self->volume, G_MOUNT_MOUNT_NONE,
+ mount_op, NULL, NULL, NULL);
+ g_object_unref (mount_op);
+ } else {
+ g_return_if_reached();
+ }
+}
+static void
+unmount_drive (DriveButton *self, GtkWidget *item)
+{
+ if (self->volume) {
+ GMount *mount;
+
+ mount = g_volume_get_mount (self->volume);
+ if (mount)
+ {
+ g_mount_unmount_with_operation (mount, G_MOUNT_UNMOUNT_NONE,
+ NULL, NULL, NULL, NULL);
+ g_object_unref (mount);
+ }
+ } else if (self->mount) {
+ g_mount_unmount_with_operation (self->mount, G_MOUNT_UNMOUNT_NONE,
+ NULL, NULL, NULL, NULL);
+ } else {
+ g_return_if_reached();
+ }
+}
+
+static void eject_finish (DriveButton *self, GAsyncResult *res,
+ gpointer user_data)
+{
+ /* Do nothing. We shouldn't need this according to the GIO
+ * docs, but the applet crashes without it using glib 2.18.0 */
+}
+
+static void
+eject_drive (DriveButton *self, GtkWidget *item)
+{
+ if (self->volume) {
+ g_volume_eject_with_operation (self->volume, G_MOUNT_UNMOUNT_NONE,
+ NULL, NULL,
+ (GAsyncReadyCallback) eject_finish,
+ NULL);
+ } else if (self->mount) {
+ g_mount_eject_with_operation (self->mount, G_MOUNT_UNMOUNT_NONE,
+ NULL, NULL,
+ (GAsyncReadyCallback) eject_finish,
+ NULL);
+ } else {
+ g_return_if_reached();
+ }
+}
+static void
+play_autoplay_media (DriveButton *self, const char *autoplay_key,
+ const char *dflt)
+{
+ MateConfClient *mateconf_client = mateconf_client_get_default ();
+ char *command = mateconf_client_get_string (mateconf_client,
+ autoplay_key, NULL);
+
+ if (!command)
+ command = g_strdup (dflt);
+
+ run_command (self, command);
+
+ g_free (command);
+ g_object_unref (mateconf_client);
+}
+
+static void
+play_dvd (DriveButton *self, GtkWidget *item)
+{
+ play_autoplay_media (self, MATECONF_ROOT_AUTOPLAY "autoplay_dvd_command",
+ "totem %d");
+}
+
+static void
+play_cda (DriveButton *self, GtkWidget *item)
+{
+ play_autoplay_media (self, MATECONF_ROOT_AUTOPLAY "autoplay_cda_command",
+ "sound-juicer -d %d");
+}
+
+static void
+drive_button_ensure_popup (DriveButton *self)
+{
+ char *display_name, *tmp, *label;
+ GtkWidget *item;
+ gboolean mounted, ejectable;
+
+ if (self->popup_menu) return;
+
+ mounted = FALSE;
+
+ if (self->volume) {
+ GMount *mount = NULL;
+
+ display_name = g_volume_get_name (self->volume);
+ ejectable = g_volume_can_eject (self->volume);
+
+ mount = g_volume_get_mount (self->volume);
+ if (mount) {
+ mounted = TRUE;
+ g_object_unref (mount);
+ }
+ } else {
+ display_name = g_mount_get_name (self->mount);
+ ejectable = g_mount_can_eject (self->mount);
+ mounted = TRUE;
+ }
+
+ self->popup_menu = gtk_menu_new ();
+
+ /* make sure the display name doesn't look like a mnemonic */
+ tmp = escape_underscores (display_name ? display_name : "(none)");
+ g_free (display_name);
+ display_name = tmp;
+
+ if (check_dvd_video (self)) {
+ item = create_menu_item (self, "media-playback-start",
+ _("_Play DVD"), G_CALLBACK (play_dvd),
+ TRUE);
+ } else if (check_audio_cd (self)) {
+ item = create_menu_item (self, "media-playback-start",
+ _("_Play CD"), G_CALLBACK (play_cda),
+ TRUE);
+ } else {
+ label = g_strdup_printf (_("_Open %s"), display_name);
+ item = create_menu_item (self, "document-open", label,
+ G_CALLBACK (open_drive), mounted);
+ g_free (label);
+ }
+ gtk_container_add (GTK_CONTAINER (self->popup_menu), item);
+
+ if (mounted) {
+ if (!ejectable) {
+ label = g_strdup_printf (_("Un_mount %s"), display_name);
+ item = create_menu_item (self, NULL, label,
+ G_CALLBACK (unmount_drive), TRUE);
+ g_free (label);
+ gtk_container_add (GTK_CONTAINER (self->popup_menu), item);
+ }
+ } else {
+ label = g_strdup_printf (_("_Mount %s"), display_name);
+ item = create_menu_item (self, NULL, label,
+ G_CALLBACK (mount_drive), TRUE);
+ g_free (label);
+ gtk_container_add (GTK_CONTAINER (self->popup_menu), item);
+ }
+
+ if (ejectable) {
+ label = g_strdup_printf (_("_Eject %s"), display_name);
+ item = create_menu_item (self, "media-eject", label,
+ G_CALLBACK (eject_drive), TRUE);
+ g_free (label);
+ gtk_container_add (GTK_CONTAINER (self->popup_menu), item);
+ }
+}