[Xfce4-commits] <thunar:master> Initial import of the shared progress dialog.
Jannis Pohlmann
jannis at xfce.org
Sun Sep 13 15:52:01 CEST 2009
Updating branch refs/heads/master
to 1fca6edc38868a1636214e41d1e6e65638bb8581 (commit)
from 1559dd2d14da591f89be1b9af3d874e593082cbc (commit)
commit 1fca6edc38868a1636214e41d1e6e65638bb8581
Author: Jannis Pohlmann <jannis at xfce.org>
Date: Sat Sep 12 15:40:35 2009 +0200
Initial import of the shared progress dialog.
This introduces a new view called ThunarProgressView which essentially
replaces the old ThunarProgressDialog. The new ThunarProgressDialog is a
container GtkWindow (I wonder about renaming it to ThunarProgressWindow)
for all the ThunarProgressViews associated with running file operations.
ThunarProgressDialog also creates a status icon that can be used to
toggle its visibility.
Things left on the TODO list:
- Check if we can lower the CPU usage of the dialog (X goes up to
around 50% on my machine with the dialog visible), compare this to
the situation before.
- Double-check if the use of gtk_window_present() is correct here.
- Either prepend (instead of append) new views or scroll down to them
upon their creation.
thunar/Makefile.am | 2 +
thunar/thunar-application.c | 62 +++--
thunar/thunar-application.h | 174 ++++++------
thunar/thunar-progress-dialog.c | 564 +++++++++++------------------------
thunar/thunar-progress-dialog.h | 52 ++--
thunar/thunar-progress-view.c | 618 +++++++++++++++++++++++++++++++++++++++
thunar/thunar-progress-view.h | 55 ++++
7 files changed, 1003 insertions(+), 524 deletions(-)
diff --git a/thunar/Makefile.am b/thunar/Makefile.am
index 241c739..b286fc5 100644
--- a/thunar/Makefile.am
+++ b/thunar/Makefile.am
@@ -146,6 +146,8 @@ Thunar_SOURCES = \
thunar-private.h \
thunar-progress-dialog.c \
thunar-progress-dialog.h \
+ thunar-progress-view.c \
+ thunar-progress-view.h \
thunar-properties-dialog.c \
thunar-properties-dialog.h \
thunar-renamer-dialog.c \
diff --git a/thunar/thunar-application.c b/thunar/thunar-application.c
index 98f01ae..a4bf914 100644
--- a/thunar/thunar-application.c
+++ b/thunar/thunar-application.c
@@ -123,6 +123,7 @@ struct _ThunarApplication
GObject __parent__;
ThunarPreferences *preferences;
+ GtkWidget *progress_dialog;
GList *windows;
gboolean daemon;
@@ -194,6 +195,7 @@ thunar_application_init (ThunarApplication *application)
application->preferences = thunar_preferences_get ();
application->files_to_launch = NULL;
+ application->progress_dialog = NULL;
/* check if we have a saved accel map */
path = xfce_resource_lookup (XFCE_RESOURCE_CONFIG, "Thunar/accels.scm");
@@ -253,7 +255,7 @@ thunar_application_finalize (GObject *object)
if (G_UNLIKELY (application->show_dialogs_timer_id != 0))
g_source_remove (application->show_dialogs_timer_id);
- /* drop the open windows */
+ /* drop the open windows (this includes the progress dialog) */
for (lp = application->windows; lp != NULL; lp = lp->next)
{
g_signal_handlers_disconnect_by_func (G_OBJECT (lp->data), G_CALLBACK (thunar_application_window_destroyed), application);
@@ -386,7 +388,6 @@ thunar_application_launch (ThunarApplication *application,
GList *target_file_list,
GClosure *new_files_closure)
{
- GtkWindow *window;
GtkWidget *dialog;
GdkScreen *screen;
ThunarJob *job;
@@ -394,7 +395,7 @@ thunar_application_launch (ThunarApplication *application,
_thunar_return_if_fail (parent == NULL || GDK_IS_SCREEN (parent) || GTK_IS_WIDGET (parent));
/* parse the parent pointer */
- screen = thunar_util_parse_parent (parent, &window);
+ screen = thunar_util_parse_parent (parent, NULL);
/* try to allocate a new job for the operation */
job = (*launcher) (source_file_list, target_file_list);
@@ -403,31 +404,23 @@ thunar_application_launch (ThunarApplication *application,
if (G_LIKELY (new_files_closure != NULL))
g_signal_connect_closure (job, "new-files", new_files_closure, FALSE);
- /* allocate a progress dialog for the job */
- dialog = g_object_new (THUNAR_TYPE_PROGRESS_DIALOG,
- "icon-name", icon_name,
- "title", title,
- "job", job,
- "screen", screen,
- NULL);
-
- /* connect to the parent (if any) */
- if (G_LIKELY (window != NULL))
- gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
+ /* get the shared progress dialog */
+ dialog = thunar_application_get_progress_dialog (application);
- /* be sure to destroy the dialog when the job is done */
- g_signal_connect_after (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), dialog);
+ /* place the dialog on the given screen */
+ if (screen != NULL)
+ gtk_window_set_screen (GTK_WINDOW (dialog), screen);
- /* hook up the dialog window */
- thunar_application_take_window (application, GTK_WINDOW (dialog));
+ thunar_progress_dialog_add_job (THUNAR_PROGRESS_DIALOG (dialog), job, icon_name, title);
/* Set up a timer to show the dialog, to make sure we don't
* just popup and destroy a dialog for a very short job.
*/
if (G_LIKELY (application->show_dialogs_timer_id == 0))
{
- application->show_dialogs_timer_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 750, thunar_application_show_dialogs,
- application, thunar_application_show_dialogs_destroy);
+ application->show_dialogs_timer_id =
+ g_timeout_add_full (G_PRIORITY_DEFAULT, 750, thunar_application_show_dialogs,
+ application, thunar_application_show_dialogs_destroy);
}
/* drop our reference on the job */
@@ -692,14 +685,12 @@ static gboolean
thunar_application_show_dialogs (gpointer user_data)
{
ThunarApplication *application = THUNAR_APPLICATION (user_data);
- GList *lp;
GDK_THREADS_ENTER ();
- /* show all progress dialogs */
- for (lp = application->windows; lp != NULL; lp = lp->next)
- if (THUNAR_IS_PROGRESS_DIALOG (lp->data))
- gtk_widget_show (GTK_WIDGET (lp->data));
+ /* show the progress dialog */
+ if (application->progress_dialog != NULL)
+ gtk_window_present (GTK_WINDOW (application->progress_dialog));
GDK_THREADS_LEAVE ();
@@ -1021,6 +1012,27 @@ thunar_application_bulk_rename (ThunarApplication *application,
+GtkWidget *
+thunar_application_get_progress_dialog (ThunarApplication *application)
+{
+ _thunar_return_val_if_fail (THUNAR_IS_APPLICATION (application), NULL);
+
+ if (application->progress_dialog == NULL)
+ {
+ application->progress_dialog = thunar_progress_dialog_new ();
+
+ g_object_add_weak_pointer (G_OBJECT (application->progress_dialog),
+ (gpointer) &application->progress_dialog);
+
+ thunar_application_take_window (application,
+ GTK_WINDOW (application->progress_dialog));
+ }
+
+ return application->progress_dialog;
+}
+
+
+
static void
thunar_application_process_files_finish (ThunarBrowser *browser,
ThunarFile *file,
diff --git a/thunar/thunar-application.h b/thunar/thunar-application.h
index d90dd28..8fdf401 100644
--- a/thunar/thunar-application.h
+++ b/thunar/thunar-application.h
@@ -36,92 +36,94 @@ typedef struct _ThunarApplication ThunarApplication;
#define THUNAR_IS_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_APPLICATION))
#define THUNAR_APPLICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_APPLICATION, ThunarApplicationClass))
-GType thunar_application_get_type (void) G_GNUC_CONST;
-
-ThunarApplication *thunar_application_get (void);
-
-gboolean thunar_application_get_daemon (ThunarApplication *application);
-void thunar_application_set_daemon (ThunarApplication *application,
- gboolean daemon);
-
-GList *thunar_application_get_windows (ThunarApplication *application);
-
-gboolean thunar_application_has_windows (ThunarApplication *application);
-
-void thunar_application_take_window (ThunarApplication *application,
- GtkWindow *window);
-
-GtkWidget *thunar_application_open_window (ThunarApplication *application,
- ThunarFile *directory,
- GdkScreen *screen,
- const gchar *startup_id);
-
-gboolean thunar_application_bulk_rename (ThunarApplication *application,
- const gchar *working_directory,
- gchar **filenames,
- gboolean standalone,
- GdkScreen *screen,
- const gchar *startup_id,
- GError **error);
-
-gboolean thunar_application_process_filenames (ThunarApplication *application,
- const gchar *working_directory,
- gchar **filenames,
- GdkScreen *screen,
- const gchar *startup_id,
- GError **error);
-
-gboolean thunar_application_is_processing (ThunarApplication *application);
-
-void thunar_application_copy_to (ThunarApplication *application,
- gpointer parent,
- GList *source_file_list,
- GList *target_file_list,
- GClosure *new_files_closure);
-
-void thunar_application_copy_into (ThunarApplication *application,
- gpointer parent,
- GList *source_file_list,
- GFile *target_file,
- GClosure *new_files_closure);
-
-void thunar_application_link_into (ThunarApplication *application,
- gpointer parent,
- GList *source_file_list,
- GFile *target_file,
- GClosure *new_files_closure);
-
-void thunar_application_move_into (ThunarApplication *application,
- gpointer parent,
- GList *source_file_list,
- GFile *target_file,
- GClosure *new_files_closure);
-
-void thunar_application_unlink_files (ThunarApplication *application,
- gpointer parent,
- GList *file_list);
-
-void thunar_application_trash (ThunarApplication *application,
- gpointer parent,
- GList *file_list);
-
-void thunar_application_creat (ThunarApplication *application,
- gpointer parent,
- GList *file_list,
- GClosure *new_files_closure);
-
-void thunar_application_mkdir (ThunarApplication *application,
- gpointer parent,
- GList *file_list,
- GClosure *new_files_closure);
-
-void thunar_application_empty_trash (ThunarApplication *application,
- gpointer parent);
-
-void thunar_application_restore_files (ThunarApplication *application,
- gpointer parent,
- GList *trash_file_list,
- GClosure *new_files_closure);
+GType thunar_application_get_type (void) G_GNUC_CONST;
+
+ThunarApplication *thunar_application_get (void);
+
+gboolean thunar_application_get_daemon (ThunarApplication *application);
+void thunar_application_set_daemon (ThunarApplication *application,
+ gboolean daemon);
+
+GList *thunar_application_get_windows (ThunarApplication *application);
+
+gboolean thunar_application_has_windows (ThunarApplication *application);
+
+void thunar_application_take_window (ThunarApplication *application,
+ GtkWindow *window);
+
+GtkWidget *thunar_application_open_window (ThunarApplication *application,
+ ThunarFile *directory,
+ GdkScreen *screen,
+ const gchar *startup_id);
+
+gboolean thunar_application_bulk_rename (ThunarApplication *application,
+ const gchar *working_directory,
+ gchar **filenames,
+ gboolean standalone,
+ GdkScreen *screen,
+ const gchar *startup_id,
+ GError **error);
+
+GtkWidget *thunar_application_get_progress_dialog (ThunarApplication *application);
+
+gboolean thunar_application_process_filenames (ThunarApplication *application,
+ const gchar *working_directory,
+ gchar **filenames,
+ GdkScreen *screen,
+ const gchar *startup_id,
+ GError **error);
+
+gboolean thunar_application_is_processing (ThunarApplication *application);
+
+void thunar_application_copy_to (ThunarApplication *application,
+ gpointer parent,
+ GList *source_file_list,
+ GList *target_file_list,
+ GClosure *new_files_closure);
+
+void thunar_application_copy_into (ThunarApplication *application,
+ gpointer parent,
+ GList *source_file_list,
+ GFile *target_file,
+ GClosure *new_files_closure);
+
+void thunar_application_link_into (ThunarApplication *application,
+ gpointer parent,
+ GList *source_file_list,
+ GFile *target_file,
+ GClosure *new_files_closure);
+
+void thunar_application_move_into (ThunarApplication *application,
+ gpointer parent,
+ GList *source_file_list,
+ GFile *target_file,
+ GClosure *new_files_closure);
+
+void thunar_application_unlink_files (ThunarApplication *application,
+ gpointer parent,
+ GList *file_list);
+
+void thunar_application_trash (ThunarApplication *application,
+ gpointer parent,
+ GList *file_list);
+
+void thunar_application_creat (ThunarApplication *application,
+ gpointer parent,
+ GList *file_list,
+ GClosure *new_files_closure);
+
+void thunar_application_mkdir (ThunarApplication *application,
+ gpointer parent,
+ GList *file_list,
+ GClosure *new_files_closure);
+
+void thunar_application_empty_trash (ThunarApplication *application,
+ gpointer parent);
+
+void thunar_application_restore_files (ThunarApplication *application,
+ gpointer parent,
+ GList *trash_file_list,
+ GClosure *new_files_closure);
G_END_DECLS;
diff --git a/thunar/thunar-progress-dialog.c b/thunar/thunar-progress-dialog.c
index 2d5b4e6..8942123 100644
--- a/thunar/thunar-progress-dialog.c
+++ b/thunar/thunar-progress-dialog.c
@@ -1,126 +1,78 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
- * Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
* Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
*
- * This program 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 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.
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#include <thunar/thunar-dialogs.h>
-#include <thunar/thunar-gobject-extensions.h>
-#include <thunar/thunar-job.h>
-#include <thunar/thunar-pango-extensions.h>
+#include <gtk/gtk.h>
+
#include <thunar/thunar-private.h>
#include <thunar/thunar-progress-dialog.h>
+#include <thunar/thunar-progress-view.h>
-enum
-{
- PROP_0,
- PROP_JOB,
-};
-
-
-
-static void thunar_progress_dialog_dispose (GObject *object);
-static void thunar_progress_dialog_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void thunar_progress_dialog_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void thunar_progress_dialog_response (GtkDialog *dialog,
- gint response);
-static ThunarJobResponse thunar_progress_dialog_ask (ThunarProgressDialog *dialog,
- const gchar *message,
- ThunarJobResponse choices,
- ThunarJob *job);
-static ThunarJobResponse thunar_progress_dialog_ask_replace (ThunarProgressDialog *dialog,
- ThunarFile *src_file,
- ThunarFile *dst_file,
- ThunarJob *job);
-static void thunar_progress_dialog_error (ThunarProgressDialog *dialog,
- GError *error,
- ExoJob *job);
-static void thunar_progress_dialog_finished (ThunarProgressDialog *dialog,
- ExoJob *job);
-static void thunar_progress_dialog_info_message (ThunarProgressDialog *dialog,
- const gchar *message,
- ExoJob *job);
-static void thunar_progress_dialog_percent (ThunarProgressDialog *dialog,
- gdouble percent,
- ExoJob *job);
+static void thunar_progress_dialog_dispose (GObject *object);
+static void thunar_progress_dialog_finalize (GObject *object);
+static gboolean thunar_progress_dialog_closed (ThunarProgressDialog *dialog);
+static gboolean thunar_progress_dialog_toggled (ThunarProgressDialog *dialog,
+ GdkEventButton *button,
+ GtkStatusIcon *status_icon);
struct _ThunarProgressDialogClass
{
- GtkDialogClass __parent__;
+ GtkWindowClass __parent__;
};
struct _ThunarProgressDialog
{
- GtkDialog __parent__;
+ GtkWindow __parent__;
- ThunarJob *job;
+ GtkStatusIcon *status_icon;
+ GtkWidget *scrollwin;
+ GtkWidget *vbox;
+ GtkWidget *content_box;
- GTimeVal start_time;
- GTimeVal last_update_time;
-
- GtkWidget *progress_bar;
- GtkWidget *progress_label;
+ GList *views;
};
-G_DEFINE_TYPE (ThunarProgressDialog, thunar_progress_dialog, GTK_TYPE_DIALOG)
+G_DEFINE_TYPE (ThunarProgressDialog, thunar_progress_dialog, GTK_TYPE_WINDOW);
static void
thunar_progress_dialog_class_init (ThunarProgressDialogClass *klass)
{
- GtkDialogClass *gtkdialog_class;
- GObjectClass *gobject_class;
+ GObjectClass *gobject_class;
+
+ /* Determine parent type class */
+ thunar_progress_dialog_parent_class = g_type_class_peek_parent (klass);
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = thunar_progress_dialog_dispose;
- gobject_class->get_property = thunar_progress_dialog_get_property;
- gobject_class->set_property = thunar_progress_dialog_set_property;
-
- gtkdialog_class = GTK_DIALOG_CLASS (klass);
- gtkdialog_class->response = thunar_progress_dialog_response;
-
- /**
- * ThunarProgressDialog:job:
- *
- * The #ThunarJob, whose progress is displayed by this dialog, or
- * %NULL if no job is set.
- **/
- g_object_class_install_property (gobject_class,
- PROP_JOB,
- g_param_spec_object ("job", "job", "job",
- THUNAR_TYPE_JOB,
- EXO_PARAM_READWRITE));
+ gobject_class->finalize = thunar_progress_dialog_finalize;
}
@@ -128,387 +80,227 @@ thunar_progress_dialog_class_init (ThunarProgressDialogClass *klass)
static void
thunar_progress_dialog_init (ThunarProgressDialog *dialog)
{
- GtkWidget *table;
- GtkWidget *image;
- GtkWidget *label;
-
- /* remember the current time as start time */
- g_get_current_time (&dialog->start_time);
-
- gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
- gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 350, -1);
- gtk_window_set_title (GTK_WINDOW (dialog), "");
-
- table = g_object_new (GTK_TYPE_TABLE,
- "border-width", 6,
- "n-columns", 3,
- "n-rows", 3,
- "row-spacing", 6,
- "column-spacing", 5,
- NULL);
- gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), table, TRUE, TRUE, 0);
- gtk_widget_show (table);
-
- image = g_object_new (GTK_TYPE_IMAGE, "icon-size", GTK_ICON_SIZE_BUTTON, NULL);
- gtk_table_attach (GTK_TABLE (table), image, 0, 1, 0, 1, GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
- gtk_widget_show (image);
-
- label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL);
- gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big ());
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 6);
- gtk_widget_show (label);
-
- dialog->progress_label = g_object_new (GTK_TYPE_LABEL, "ellipsize", PANGO_ELLIPSIZE_START, "xalign", 0.0f, NULL);
- gtk_table_attach (GTK_TABLE (table), dialog->progress_label, 0, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (dialog->progress_label);
-
- dialog->progress_bar = g_object_new (GTK_TYPE_PROGRESS_BAR, "text", " ", NULL);
- gtk_table_attach (GTK_TABLE (table), dialog->progress_bar, 0, 2, 2, 3, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
- gtk_widget_show (dialog->progress_bar);
-
- /* connect the window icon name to the action image */
- exo_binding_new (G_OBJECT (dialog), "icon-name",
- G_OBJECT (image), "icon-name");
-
- /* connect the window title to the action label */
- exo_binding_new (G_OBJECT (dialog), "title",
- G_OBJECT (label), "label");
-}
+ dialog->views = NULL;
+ gtk_window_set_title (GTK_WINDOW (dialog), _("File Operation Progress"));
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 10);
+ gtk_window_set_modal (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), NULL);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (thunar_progress_dialog_closed), dialog);
-static void
-thunar_progress_dialog_dispose (GObject *object)
-{
- ThunarProgressDialog *dialog = THUNAR_PROGRESS_DIALOG (object);
+ dialog->vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (dialog), dialog->vbox);
+ gtk_widget_show (dialog->vbox);
- /* disconnect from the job (if any) */
- thunar_progress_dialog_set_job (dialog, NULL);
+ dialog->content_box = gtk_vbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog->content_box), 8);
+ gtk_container_add (GTK_CONTAINER (dialog->vbox), dialog->content_box);
+ gtk_widget_show (dialog->content_box);
- (*G_OBJECT_CLASS (thunar_progress_dialog_parent_class)->dispose) (object);
+ dialog->status_icon = gtk_status_icon_new_from_stock (GTK_STOCK_DIRECTORY);
+ gtk_status_icon_set_visible (dialog->status_icon, FALSE);
+
+ g_signal_connect_swapped (dialog->status_icon, "button-press-event",
+ G_CALLBACK (thunar_progress_dialog_toggled),
+ GTK_WIDGET (dialog));
}
static void
-thunar_progress_dialog_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+thunar_progress_dialog_dispose (GObject *object)
{
- ThunarProgressDialog *dialog = THUNAR_PROGRESS_DIALOG (object);
-
- switch (prop_id)
- {
- case PROP_JOB:
- g_value_set_object (value, thunar_progress_dialog_get_job (dialog));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ (*G_OBJECT_CLASS (thunar_progress_dialog_parent_class)->dispose) (object);
}
static void
-thunar_progress_dialog_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
+thunar_progress_dialog_finalize (GObject *object)
{
ThunarProgressDialog *dialog = THUNAR_PROGRESS_DIALOG (object);
- switch (prop_id)
- {
- case PROP_JOB:
- thunar_progress_dialog_set_job (dialog, g_value_get_object (value));
- break;
+ /* destroy the status icon */
+ g_object_unref (dialog->status_icon);
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ /* free the view list */
+ g_list_free (dialog->views);
+
+ (*G_OBJECT_CLASS (thunar_progress_dialog_parent_class)->finalize) (object);
}
-static ThunarJobResponse
-thunar_progress_dialog_ask (ThunarProgressDialog *dialog,
- const gchar *message,
- ThunarJobResponse choices,
- ThunarJob *job)
+static gboolean
+thunar_progress_dialog_closed (ThunarProgressDialog *dialog)
{
- _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (g_utf8_validate (message, -1, NULL), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (dialog->job == job, THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog), FALSE);
- /* be sure to display the progress dialog prior to opening the question dialog */
- gtk_widget_show_now (GTK_WIDGET (dialog));
+ /* hide the progress dialog */
+ gtk_widget_hide (GTK_WIDGET (dialog));
- /* display the question dialog */
- return thunar_dialogs_show_job_ask (GTK_WINDOW (dialog), message, choices);
+ /* don't destroy the dialog */
+ return TRUE;
}
-static ThunarJobResponse
-thunar_progress_dialog_ask_replace (ThunarProgressDialog *dialog,
- ThunarFile *src_file,
- ThunarFile *dst_file,
- ThunarJob *job)
+static gboolean
+thunar_progress_dialog_toggled (ThunarProgressDialog *dialog,
+ GdkEventButton *event,
+ GtkStatusIcon *status_icon)
{
- _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (dialog->job == job, THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (THUNAR_IS_FILE (src_file), THUNAR_JOB_RESPONSE_CANCEL);
- _thunar_return_val_if_fail (THUNAR_IS_FILE (dst_file), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog), FALSE);
+ _thunar_return_val_if_fail (GTK_IS_STATUS_ICON (status_icon), FALSE);
- /* be sure to display the progress dialog prior to opening the question dialog */
- gtk_widget_show_now (GTK_WIDGET (dialog));
+ /* toggle the visibility of the progress dialog */
+ if (GTK_WIDGET_VISIBLE (GTK_WIDGET (dialog)))
+ gtk_widget_hide (GTK_WIDGET (dialog));
+ else
+ gtk_widget_show (GTK_WIDGET (dialog));
- /* display the question dialog */
- return thunar_dialogs_show_job_ask_replace (GTK_WINDOW (dialog), src_file, dst_file);
+ return TRUE;
}
static void
-thunar_progress_dialog_error (ThunarProgressDialog *dialog,
- GError *error,
- ExoJob *job)
+thunar_progress_dialog_view_needs_attention (ThunarProgressDialog *dialog,
+ ThunarProgressView *view)
{
_thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
- _thunar_return_if_fail (error != NULL && error->message != NULL);
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
- _thunar_return_if_fail (dialog->job == THUNAR_JOB (job));
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
- /* be sure to display the progress dialog prior to opening the error dialog */
- gtk_widget_show_now (GTK_WIDGET (dialog));
+ /* TODO scroll to the view */
- /* display the error message */
- thunar_dialogs_show_job_error (GTK_WINDOW (dialog), error);
+ /* raise the dialog */
+ gtk_window_present (GTK_WINDOW (dialog));
}
static void
-thunar_progress_dialog_finished (ThunarProgressDialog *dialog,
- ExoJob *job)
+thunar_progress_dialog_job_finished (ThunarProgressDialog *dialog,
+ ThunarProgressView *view)
{
- _thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
- _thunar_return_if_fail (dialog->job == THUNAR_JOB (job));
-
- gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
-}
-
+ guint n_views;
-
-static void
-thunar_progress_dialog_info_message (ThunarProgressDialog *dialog,
- const gchar *message,
- ExoJob *job)
-{
_thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
- _thunar_return_if_fail (g_utf8_validate (message, -1, NULL));
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
- _thunar_return_if_fail (dialog->job == THUNAR_JOB (job));
-
- gtk_label_set_text (GTK_LABEL (dialog->progress_label), message);
-}
-
-
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
-static inline guint64
-time_diff (const GTimeVal *now,
- const GTimeVal *last)
-{
- return ((guint64) now->tv_sec - last->tv_sec) * G_USEC_PER_SEC
- + ((guint64) last->tv_usec - last->tv_usec);
-}
+ /* remove the view from the list */
+ dialog->views = g_list_remove (dialog->views, view);
+ /* destroy the widget */
+ gtk_widget_destroy (GTK_WIDGET (view));
+ /* determine the number of views left */
+ n_views = g_list_length (dialog->views);
-static void
-thunar_progress_dialog_percent (ThunarProgressDialog *dialog,
- gdouble percent,
- ExoJob *job)
-{
- GTimeVal current_time;
- gulong remaining_time;
- gulong elapsed_time;
- gchar text[512];
-
- _thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
- _thunar_return_if_fail (percent >= 0.0 && percent <= 100.0);
- _thunar_return_if_fail (THUNAR_IS_JOB (job));
- _thunar_return_if_fail (dialog->job == THUNAR_JOB (job));
-
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dialog->progress_bar), percent / 100.0);
-
- /* check if we should update the time display (every 400ms) */
- g_get_current_time (¤t_time);
- if (time_diff (¤t_time, &dialog->last_update_time) > 400 * 1000)
+ /* check if we've just removed the 4th view and are now left with
+ * 3 of them, in which case we drop the scroll window */
+ if (n_views == 3)
{
- /* calculate the remaining time (in seconds) */
- elapsed_time = time_diff (¤t_time, &dialog->start_time) / 1000;
- remaining_time = ((100 * elapsed_time) / percent - elapsed_time) / 1000;
-
- /* setup the time label */
- if (G_LIKELY (remaining_time > 0))
- {
- /* format the time text */
- if (remaining_time > 60 * 60)
- {
- remaining_time = (gulong) (remaining_time / (60 * 60));
- g_snprintf (text, sizeof (text), ngettext ("(%lu hour remaining)", "(%lu hours remaining)", remaining_time), remaining_time);
- }
- else if (remaining_time > 60)
- {
- remaining_time = (gulong) (remaining_time / 60);
- g_snprintf (text, sizeof (text), ngettext ("(%lu minute remaining)", "(%lu minutes remaining)", remaining_time), remaining_time);
- }
- else
- {
- remaining_time = remaining_time;
- g_snprintf (text, sizeof (text), ngettext ("(%lu second remaining)", "(%lu seconds remaining)", remaining_time), remaining_time);
- }
-
- /* apply the time text */
- gtk_progress_bar_set_text (GTK_PROGRESS_BAR (dialog->progress_bar), text);
- }
- else
- {
- /* display an empty label */
- gtk_progress_bar_set_text (GTK_PROGRESS_BAR (dialog->progress_bar), " ");
- }
-
- /* remember the current time as last update time */
- dialog->last_update_time = current_time;
- }
-}
-
+ /* reparent the content box */
+ gtk_widget_reparent (dialog->content_box, dialog->vbox);
+ /* destroy the scroll win */
+ gtk_widget_destroy (dialog->scrollwin);
+ }
-static void
-thunar_progress_dialog_response (GtkDialog *dialog,
- gint response)
-{
- /* cancel the job appropriately */
- switch (response)
+ /* check if we have less than 4 views and need to shrink the window */
+ if (n_views <= 3)
{
- case GTK_RESPONSE_NONE:
- case GTK_RESPONSE_REJECT:
- case GTK_RESPONSE_DELETE_EVENT:
- case GTK_RESPONSE_CANCEL:
- case GTK_RESPONSE_CLOSE:
- case GTK_RESPONSE_NO:
- if (G_LIKELY (THUNAR_PROGRESS_DIALOG (dialog)->job != NULL))
- exo_job_cancel (EXO_JOB (THUNAR_PROGRESS_DIALOG (dialog)->job));
- break;
+ /* try to shrink the window */
+ gtk_window_resize (GTK_WINDOW (dialog), 400, 10);
}
- if (GTK_DIALOG_CLASS (thunar_progress_dialog_parent_class)->response != NULL)
- (*GTK_DIALOG_CLASS (thunar_progress_dialog_parent_class)->response) (dialog, response);
+ /* destroy the dialog if there are no views left */
+ if (dialog->views == NULL)
+ gtk_widget_destroy (GTK_WIDGET (dialog));
}
-/**
- * thunar_progress_dialog_new:
- *
- * Allocates a new #ThunarProgressDialog.
- *
- * Return value: the newly allocated #ThunarProgressDialog.
- **/
GtkWidget*
thunar_progress_dialog_new (void)
{
- return thunar_progress_dialog_new_with_job (NULL);
-}
-
-
-
-/**
- * thunar_progress_dialog_new_with_job:
- * @job : a #ThunarJob or %NULL.
- *
- * Allocates a new #ThunarProgressDialog and associates it with the @job.
- *
- * Return value: the newly allocated #ThunarProgressDialog.
- **/
-GtkWidget*
-thunar_progress_dialog_new_with_job (ThunarJob *job)
-{
- _thunar_return_val_if_fail (job == NULL || THUNAR_IS_JOB (job), NULL);
- return g_object_new (THUNAR_TYPE_PROGRESS_DIALOG, "job", job, NULL);
-}
-
-
-
-/**
- * thunar_progress_dialog_get_job:
- * @dialog : a #ThunarProgressDialog.
- *
- * Returns the #ThunarJob associated with @dialog
- * or %NULL if no job is currently associated with @dialog.
- *
- * Return value: the job associated with @dialog or %NULL.
- **/
-ThunarJob *
-thunar_progress_dialog_get_job (ThunarProgressDialog *dialog)
-{
- _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog), NULL);
- return dialog->job;
+ return g_object_new (THUNAR_TYPE_PROGRESS_DIALOG, NULL);
}
-/**
- * thunar_progress_dialog_set_job:
- * @dialog : a #ThunarProgressDialog.
- * @job : a #ThunarJob or %NULL.
- *
- * Associates @job with @dialog.
- **/
void
-thunar_progress_dialog_set_job (ThunarProgressDialog *dialog,
- ThunarJob *job)
+thunar_progress_dialog_add_job (ThunarProgressDialog *dialog,
+ ThunarJob *job,
+ const gchar *icon_name,
+ const gchar *title)
{
- _thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
- _thunar_return_if_fail (job == NULL || THUNAR_IS_JOB (job));
-
- /* check if we're already on that job */
- if (G_UNLIKELY (dialog->job == job))
- return;
+ GtkWidget *viewport;
+ GtkWidget *view;
+ gchar *tooltip_text;
+ guint n_views;
- /* disconnect from the previous job */
- if (G_LIKELY (dialog->job != NULL))
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_DIALOG (dialog));
+ _thunar_return_if_fail (THUNAR_IS_JOB (job));
+ _thunar_return_if_fail (g_utf8_validate (title, -1, NULL));
+
+ view = thunar_progress_view_new_with_job (job);
+ thunar_progress_view_set_icon_name (THUNAR_PROGRESS_VIEW (view), icon_name);
+ thunar_progress_view_set_title (THUNAR_PROGRESS_VIEW (view), title);
+ gtk_box_pack_start (GTK_BOX (dialog->content_box), view, FALSE, TRUE, 0);
+ gtk_widget_show (view);
+
+ /* add the view to the list of known views */
+ dialog->views = g_list_prepend (dialog->views, view);
+
+ /* determine the number of views now being active */
+ n_views = g_list_length (dialog->views);
+
+ /* check if we need to wrap the views in a scroll window (starting
+ * at 4 parallel operations */
+ if (n_views == 4)
{
- g_signal_handlers_disconnect_matched (dialog->job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dialog);
- g_object_unref (G_OBJECT (dialog->job));
+ /* create a scrolled window and add it to the dialog */
+ dialog->scrollwin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (dialog->scrollwin),
+ GTK_SHADOW_NONE);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (dialog->scrollwin),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (dialog->vbox), dialog->scrollwin);
+ gtk_widget_show (dialog->scrollwin);
+
+ /* create a viewport for the content box */
+ viewport = gtk_viewport_new (gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (dialog->scrollwin)),
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (dialog->scrollwin)));
+ gtk_container_add (GTK_CONTAINER (dialog->scrollwin), viewport);
+ gtk_widget_show (viewport);
+
+ /* move the content box into the viewport */
+ gtk_widget_reparent (dialog->content_box, viewport);
}
- /* activate the new job */
- dialog->job = job;
+ g_signal_connect_swapped (view, "need-attention",
+ G_CALLBACK (thunar_progress_dialog_view_needs_attention), dialog);
- /* connect to the new job */
- if (G_LIKELY (job != NULL))
- {
- g_object_ref (job);
-
- g_signal_connect_swapped (job, "ask", G_CALLBACK (thunar_progress_dialog_ask), dialog);
- g_signal_connect_swapped (job, "ask-replace", G_CALLBACK (thunar_progress_dialog_ask_replace), dialog);
- g_signal_connect_swapped (job, "error", G_CALLBACK (thunar_progress_dialog_error), dialog);
- g_signal_connect_swapped (job, "finished", G_CALLBACK (thunar_progress_dialog_finished), dialog);
- g_signal_connect_swapped (job, "info-message", G_CALLBACK (thunar_progress_dialog_info_message), dialog);
- g_signal_connect_swapped (job, "percent", G_CALLBACK (thunar_progress_dialog_percent), dialog);
- }
+ g_signal_connect_swapped (view, "finished",
+ G_CALLBACK (thunar_progress_dialog_job_finished), dialog);
- g_object_notify (G_OBJECT (dialog), "job");
-}
+ /* make the status icon visible */
+ gtk_status_icon_set_visible (dialog->status_icon, TRUE);
+ /* set status icon tooltip */
+ tooltip_text = g_strdup_printf (ngettext ("1 file operation running", "%d file operations running",
+ n_views),
+ n_views);
+#if GTK_CHECK_VERSION (2, 16, 0)
+ gtk_status_icon_set_tooltip_text (dialog->status_icon, tooltip_text);
+#else
+ gtk_status_icon_set_tooltip (dialog->status_icon, tooltip_text);
+#endif
+ g_free (tooltip_text);
+}
diff --git a/thunar/thunar-progress-dialog.h b/thunar/thunar-progress-dialog.h
index cb1dd51..e4bdbf8 100644
--- a/thunar/thunar-progress-dialog.h
+++ b/thunar/thunar-progress-dialog.h
@@ -1,28 +1,27 @@
-/* $Id$ */
+/* vi:set et ai sw=2 sts=2 ts=2: */
/*-
- * Copyright (c) 2005 Benedikt Meurer <benny at xfce.org>
* Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
*
- * This program 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 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.
+ * 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
+ * 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*/
#ifndef __THUNAR_PROGRESS_DIALOG_H__
#define __THUNAR_PROGRESS_DIALOG_H__
#include <gtk/gtk.h>
-
#include <thunar/thunar-job.h>
G_BEGIN_DECLS;
@@ -30,21 +29,20 @@ G_BEGIN_DECLS;
typedef struct _ThunarProgressDialogClass ThunarProgressDialogClass;
typedef struct _ThunarProgressDialog ThunarProgressDialog;
-#define THUNAR_TYPE_PROGRESS_DIALOG (thunar_progress_dialog_get_type ())
-#define THUNAR_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialog))
-#define THUNAR_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialogClass))
-#define THUNAR_IS_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_PROGRESS_DIALOG))
-#define THUNAR_IS_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_PROGRESS_DIALOG))
-#define THUNAR_PROGRESS_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialogClass))
-
-GType thunar_progress_dialog_get_type (void) G_GNUC_CONST;
+#define THUNAR_TYPE_PROGRESS_DIALOG (thunar_progress_dialog_get_type ())
+#define THUNAR_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialog))
+#define THUNAR_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialogClass))
+#define THUNAR_IS_PROGRESS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_PROGRESS_DIALOG))
+#define THUNAR_IS_PROGRESS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_PROGRESS_DIALOG))
+#define THUNAR_PROGRESS_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_PROGRESS_DIALOG, ThunarProgressDialogClass))
-GtkWidget *thunar_progress_dialog_new (void) G_GNUC_MALLOC;
-GtkWidget *thunar_progress_dialog_new_with_job (ThunarJob *job) G_GNUC_MALLOC;
+GType thunar_progress_dialog_get_type (void) G_GNUC_CONST;
-ThunarJob *thunar_progress_dialog_get_job (ThunarProgressDialog *dialog);
-void thunar_progress_dialog_set_job (ThunarProgressDialog *dialog,
- ThunarJob *job);
+GtkWidget *thunar_progress_dialog_new (void);
+void thunar_progress_dialog_add_job (ThunarProgressDialog *dialog,
+ ThunarJob *job,
+ const gchar *icon_name,
+ const gchar *title);
G_END_DECLS;
diff --git a/thunar/thunar-progress-view.c b/thunar/thunar-progress-view.c
new file mode 100644
index 0000000..5a0f989
--- /dev/null
+++ b/thunar/thunar-progress-view.c
@@ -0,0 +1,618 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005-2007 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This program 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <exo/exo.h>
+
+#include <thunar/thunar-dialogs.h>
+#include <thunar/thunar-gobject-extensions.h>
+#include <thunar/thunar-job.h>
+#include <thunar/thunar-pango-extensions.h>
+#include <thunar/thunar-private.h>
+#include <thunar/thunar-progress-view.h>
+
+
+
+enum
+{
+ PROP_0,
+ PROP_JOB,
+ PROP_ICON_NAME,
+ PROP_TITLE,
+};
+
+
+
+static void thunar_progress_view_dispose (GObject *object);
+static void thunar_progress_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void thunar_progress_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void thunar_progress_view_cancel_job (ThunarProgressView *view);
+static ThunarJobResponse thunar_progress_view_ask (ThunarProgressView *view,
+ const gchar *message,
+ ThunarJobResponse choices,
+ ThunarJob *job);
+static ThunarJobResponse thunar_progress_view_ask_replace (ThunarProgressView *view,
+ ThunarFile *src_file,
+ ThunarFile *dst_file,
+ ThunarJob *job);
+static void thunar_progress_view_error (ThunarProgressView *view,
+ GError *error,
+ ExoJob *job);
+static void thunar_progress_view_finished (ThunarProgressView *view,
+ ExoJob *job);
+static void thunar_progress_view_info_message (ThunarProgressView *view,
+ const gchar *message,
+ ExoJob *job);
+static void thunar_progress_view_percent (ThunarProgressView *view,
+ gdouble percent,
+ ExoJob *job);
+
+
+
+struct _ThunarProgressViewClass
+{
+ GtkVBoxClass __parent__;
+};
+
+struct _ThunarProgressView
+{
+ GtkVBox __parent__;
+
+ ThunarJob *job;
+
+ GTimeVal start_time;
+ GTimeVal last_update_time;
+
+ GtkWidget *progress_bar;
+ GtkWidget *progress_label;
+
+ gchar *icon_name;
+ gchar *title;
+};
+
+
+
+G_DEFINE_TYPE (ThunarProgressView, thunar_progress_view, GTK_TYPE_VBOX)
+
+
+
+static void
+thunar_progress_view_class_init (ThunarProgressViewClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->dispose = thunar_progress_view_dispose;
+ gobject_class->get_property = thunar_progress_view_get_property;
+ gobject_class->set_property = thunar_progress_view_set_property;
+
+ /**
+ * ThunarProgressView:job:
+ *
+ * The #ThunarJob, whose progress is displayed by this view, or
+ * %NULL if no job is set.
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_JOB,
+ g_param_spec_object ("job", "job", "job",
+ THUNAR_TYPE_JOB,
+ EXO_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_ICON_NAME,
+ g_param_spec_string ("icon-name",
+ "icon-name",
+ "icon-name",
+ NULL,
+ EXO_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_TITLE,
+ g_param_spec_string ("title",
+ "title",
+ "title",
+ NULL,
+ EXO_PARAM_READWRITE));
+
+ g_signal_new ("need-attention",
+ THUNAR_TYPE_PROGRESS_VIEW,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_signal_new ("finished",
+ THUNAR_TYPE_PROGRESS_VIEW,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+
+
+static void
+thunar_progress_view_init (ThunarProgressView *view)
+{
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *button;
+ GtkWidget *vbox;
+ GtkWidget *vbox2;
+ GtkWidget *hbox;
+
+ /* remember the current time as start time */
+ g_get_current_time (&view->start_time);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (view), vbox);
+ gtk_widget_show (vbox);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ image = g_object_new (GTK_TYPE_IMAGE, "icon-size", GTK_ICON_SIZE_BUTTON, NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
+ gtk_widget_show (image);
+
+ vbox2 = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, TRUE, 0);
+ gtk_widget_show (vbox2);
+
+ label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL);
+ gtk_label_set_attributes (GTK_LABEL (label), thunar_pango_attr_list_big_bold ());
+ gtk_box_pack_start (GTK_BOX (vbox2), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ view->progress_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2), view->progress_label, FALSE, TRUE, 0);
+ gtk_widget_show (view->progress_label);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ view->progress_bar = g_object_new (GTK_TYPE_PROGRESS_BAR, "text", " ", NULL);
+ gtk_box_pack_start (GTK_BOX (hbox), view->progress_bar, TRUE, TRUE, 0);
+ gtk_widget_show (view->progress_bar);
+
+ button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+ g_signal_connect_swapped (button, "clicked", G_CALLBACK (thunar_progress_view_cancel_job), view);
+ gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, TRUE, 0);
+ gtk_widget_show (button);
+
+ /* connect the view icon name to the action image */
+ exo_binding_new (G_OBJECT (view), "icon-name", G_OBJECT (image), "icon-name");
+
+ /* connect the view title to the action label */
+ exo_binding_new (G_OBJECT (view), "title", G_OBJECT (label), "label");
+}
+
+
+
+static void
+thunar_progress_view_dispose (GObject *object)
+{
+ ThunarProgressView *view = THUNAR_PROGRESS_VIEW (object);
+
+ /* disconnect from the job (if any) */
+ if (view->job != NULL)
+ {
+ exo_job_cancel (EXO_JOB (view->job));
+ thunar_progress_view_set_job (view, NULL);
+ }
+
+ (*G_OBJECT_CLASS (thunar_progress_view_parent_class)->dispose) (object);
+}
+
+
+
+static void
+thunar_progress_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ThunarProgressView *view = THUNAR_PROGRESS_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_JOB:
+ g_value_set_object (value, thunar_progress_view_get_job (view));
+ break;
+
+ case PROP_ICON_NAME:
+ g_value_set_string (value, view->icon_name);
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, view->title);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+thunar_progress_view_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ThunarProgressView *view = THUNAR_PROGRESS_VIEW (object);
+
+ switch (prop_id)
+ {
+ case PROP_JOB:
+ thunar_progress_view_set_job (view, g_value_get_object (value));
+ break;
+
+ case PROP_ICON_NAME:
+ thunar_progress_view_set_icon_name (view, g_value_get_string (value));
+ break;
+
+ case PROP_TITLE:
+ thunar_progress_view_set_title (view, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+thunar_progress_view_cancel_job (ThunarProgressView *view)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (THUNAR_IS_JOB (view->job));
+
+ if (view->job != NULL)
+ exo_job_cancel (EXO_JOB (view->job));
+}
+
+
+
+static ThunarJobResponse
+thunar_progress_view_ask (ThunarProgressView *view,
+ const gchar *message,
+ ThunarJobResponse choices,
+ ThunarJob *job)
+{
+ GtkWidget *window;
+
+ _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_VIEW (view), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (g_utf8_validate (message, -1, NULL), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (view->job == job, THUNAR_JOB_RESPONSE_CANCEL);
+
+ /* be sure to display the corresponding dialog prior to opening the question view */
+ g_signal_emit_by_name (view, "need-attention");
+
+ /* determine the toplevel window of the view */
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ /* display the question view */
+ return thunar_dialogs_show_job_ask (window != NULL ? GTK_WINDOW (window) : NULL,
+ message, choices);
+}
+
+
+
+static ThunarJobResponse
+thunar_progress_view_ask_replace (ThunarProgressView *view,
+ ThunarFile *src_file,
+ ThunarFile *dst_file,
+ ThunarJob *job)
+{
+ GtkWidget *window;
+
+ _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_VIEW (view), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_JOB (job), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (view->job == job, THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_FILE (src_file), THUNAR_JOB_RESPONSE_CANCEL);
+ _thunar_return_val_if_fail (THUNAR_IS_FILE (dst_file), THUNAR_JOB_RESPONSE_CANCEL);
+
+ /* be sure to display the corresponding dialog prior to opening the question view */
+ g_signal_emit_by_name (view, "need-attention");
+
+ /* determine the toplevel window of the view */
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ /* display the question view */
+ return thunar_dialogs_show_job_ask_replace (window != NULL ? GTK_WINDOW (window) : NULL,
+ src_file, dst_file);
+}
+
+
+
+static void
+thunar_progress_view_error (ThunarProgressView *view,
+ GError *error,
+ ExoJob *job)
+{
+ GtkWidget *window;
+
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (error != NULL && error->message != NULL);
+ _thunar_return_if_fail (THUNAR_IS_JOB (job));
+ _thunar_return_if_fail (view->job == THUNAR_JOB (job));
+
+ /* be sure to display the corresponding dialog prior to opening the question view */
+ g_signal_emit_by_name (view, "need-attention");
+
+ /* determine the toplevel window of the view */
+ window = gtk_widget_get_toplevel (GTK_WIDGET (view));
+
+ /* display the error message */
+ thunar_dialogs_show_job_error (window != NULL ? GTK_WINDOW (window) : NULL, error);
+}
+
+
+
+static void
+thunar_progress_view_finished (ThunarProgressView *view,
+ ExoJob *job)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (THUNAR_IS_JOB (job));
+ _thunar_return_if_fail (view->job == THUNAR_JOB (job));
+
+ /* emit finished signal to notify others that the job is finished */
+ g_signal_emit_by_name (view, "finished");
+}
+
+
+
+static void
+thunar_progress_view_info_message (ThunarProgressView *view,
+ const gchar *message,
+ ExoJob *job)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (g_utf8_validate (message, -1, NULL));
+ _thunar_return_if_fail (THUNAR_IS_JOB (job));
+ _thunar_return_if_fail (view->job == THUNAR_JOB (job));
+
+ gtk_label_set_text (GTK_LABEL (view->progress_label), message);
+}
+
+
+
+static inline guint64
+time_diff (const GTimeVal *now,
+ const GTimeVal *last)
+{
+ return ((guint64) now->tv_sec - last->tv_sec) * G_USEC_PER_SEC
+ + ((guint64) last->tv_usec - last->tv_usec);
+}
+
+
+
+static void
+thunar_progress_view_percent (ThunarProgressView *view,
+ gdouble percent,
+ ExoJob *job)
+{
+ GTimeVal current_time;
+ gulong remaining_time;
+ gulong elapsed_time;
+ gchar text[512];
+
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (percent >= 0.0 && percent <= 100.0);
+ _thunar_return_if_fail (THUNAR_IS_JOB (job));
+ _thunar_return_if_fail (view->job == THUNAR_JOB (job));
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (view->progress_bar), percent / 100.0);
+
+ /* check if we should update the time display (every 400ms) */
+ g_get_current_time (¤t_time);
+ if (time_diff (¤t_time, &view->last_update_time) > 400 * 1000)
+ {
+ /* calculate the remaining time (in seconds) */
+ elapsed_time = time_diff (¤t_time, &view->start_time) / 1000;
+ remaining_time = ((100 * elapsed_time) / percent - elapsed_time) / 1000;
+
+ /* setup the time label */
+ if (G_LIKELY (remaining_time > 0))
+ {
+ /* format the time text */
+ if (remaining_time > 60 * 60)
+ {
+ remaining_time = (gulong) (remaining_time / (60 * 60));
+ g_snprintf (text, sizeof (text), ngettext ("(%lu hour remaining)", "(%lu hours remaining)", remaining_time), remaining_time);
+ }
+ else if (remaining_time > 60)
+ {
+ remaining_time = (gulong) (remaining_time / 60);
+ g_snprintf (text, sizeof (text), ngettext ("(%lu minute remaining)", "(%lu minutes remaining)", remaining_time), remaining_time);
+ }
+ else
+ {
+ remaining_time = remaining_time;
+ g_snprintf (text, sizeof (text), ngettext ("(%lu second remaining)", "(%lu seconds remaining)", remaining_time), remaining_time);
+ }
+
+ /* apply the time text */
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (view->progress_bar), text);
+ }
+ else
+ {
+ /* display an empty label */
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (view->progress_bar), " ");
+ }
+
+ /* remember the current time as last update time */
+ view->last_update_time = current_time;
+ }
+}
+
+
+
+/**
+ * thunar_progress_view_new:
+ *
+ * Allocates a new #ThunarProgressView.
+ *
+ * Return value: the newly allocated #ThunarProgressView.
+ **/
+GtkWidget*
+thunar_progress_view_new (void)
+{
+ return thunar_progress_view_new_with_job (NULL);
+}
+
+
+
+/**
+ * thunar_progress_view_new_with_job:
+ * @job : a #ThunarJob or %NULL.
+ *
+ * Allocates a new #ThunarProgressView and associates it with the @job.
+ *
+ * Return value: the newly allocated #ThunarProgressView.
+ **/
+GtkWidget*
+thunar_progress_view_new_with_job (ThunarJob *job)
+{
+ _thunar_return_val_if_fail (job == NULL || THUNAR_IS_JOB (job), NULL);
+ return g_object_new (THUNAR_TYPE_PROGRESS_VIEW, "job", job, NULL);
+}
+
+
+
+/**
+ * thunar_progress_view_get_job:
+ * @view : a #ThunarProgressView.
+ *
+ * Returns the #ThunarJob associated with @view
+ * or %NULL if no job is currently associated with @view.
+ *
+ * Return value: the job associated with @view or %NULL.
+ **/
+ThunarJob *
+thunar_progress_view_get_job (ThunarProgressView *view)
+{
+ _thunar_return_val_if_fail (THUNAR_IS_PROGRESS_VIEW (view), NULL);
+ return view->job;
+}
+
+
+
+/**
+ * thunar_progress_view_set_job:
+ * @view : a #ThunarProgressView.
+ * @job : a #ThunarJob or %NULL.
+ *
+ * Associates @job with @view.
+ **/
+void
+thunar_progress_view_set_job (ThunarProgressView *view,
+ ThunarJob *job)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+ _thunar_return_if_fail (job == NULL || THUNAR_IS_JOB (job));
+
+ /* check if we're already on that job */
+ if (G_UNLIKELY (view->job == job))
+ return;
+
+ /* disconnect from the previous job */
+ if (G_LIKELY (view->job != NULL))
+ {
+ g_signal_handlers_disconnect_matched (view->job, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+ g_object_unref (G_OBJECT (view->job));
+ }
+
+ /* activate the new job */
+ view->job = job;
+
+ /* connect to the new job */
+ if (G_LIKELY (job != NULL))
+ {
+ g_object_ref (job);
+
+ g_signal_connect_swapped (job, "ask", G_CALLBACK (thunar_progress_view_ask), view);
+ g_signal_connect_swapped (job, "ask-replace", G_CALLBACK (thunar_progress_view_ask_replace), view);
+ g_signal_connect_swapped (job, "error", G_CALLBACK (thunar_progress_view_error), view);
+ g_signal_connect_swapped (job, "finished", G_CALLBACK (thunar_progress_view_finished), view);
+ g_signal_connect_swapped (job, "info-message", G_CALLBACK (thunar_progress_view_info_message), view);
+ g_signal_connect_swapped (job, "percent", G_CALLBACK (thunar_progress_view_percent), view);
+ }
+
+ g_object_notify (G_OBJECT (view), "job");
+}
+
+
+
+void
+thunar_progress_view_set_icon_name (ThunarProgressView *view,
+ const gchar *icon_name)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+
+ if (exo_str_is_equal (view->icon_name, icon_name))
+ return;
+
+ g_free (view->icon_name);
+ view->icon_name = g_strdup (icon_name);
+
+ g_object_notify (G_OBJECT (view), "icon-name");
+}
+
+
+
+void
+thunar_progress_view_set_title (ThunarProgressView *view,
+ const gchar *title)
+{
+ _thunar_return_if_fail (THUNAR_IS_PROGRESS_VIEW (view));
+
+ if (exo_str_is_equal (view->title, title))
+ return;
+
+ g_free (view->title);
+ view->title = g_strdup (title);
+
+ g_object_notify (G_OBJECT (view), "title");
+}
diff --git a/thunar/thunar-progress-view.h b/thunar/thunar-progress-view.h
new file mode 100644
index 0000000..096a44c
--- /dev/null
+++ b/thunar/thunar-progress-view.h
@@ -0,0 +1,55 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2005 Benedikt Meurer <benny at xfce.org>
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ *
+ * This program 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
+ */
+
+#ifndef __THUNAR_PROGRESS_VIEW_H__
+#define __THUNAR_PROGRESS_VIEW_H__
+
+#include <gtk/gtk.h>
+
+#include <thunar/thunar-job.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _ThunarProgressViewClass ThunarProgressViewClass;
+typedef struct _ThunarProgressView ThunarProgressView;
+
+#define THUNAR_TYPE_PROGRESS_VIEW (thunar_progress_view_get_type ())
+#define THUNAR_PROGRESS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_PROGRESS_VIEW, ThunarProgressView))
+#define THUNAR_PROGRESS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_PROGRESS_VIEW, ThunarProgressViewClass))
+#define THUNAR_IS_PROGRESS_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_PROGRESS_VIEW))
+#define THUNAR_IS_PROGRESS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_PROGRESS_VIEW))
+#define THUNAR_PROGRESS_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_PROGRESS_VIEW, ThunarProgressViewClass))
+
+GType thunar_progress_view_get_type (void) G_GNUC_CONST;
+
+GtkWidget *thunar_progress_view_new (void) G_GNUC_MALLOC;
+GtkWidget *thunar_progress_view_new_with_job (ThunarJob *job) G_GNUC_MALLOC;
+
+ThunarJob *thunar_progress_view_get_job (ThunarProgressView *view);
+void thunar_progress_view_set_job (ThunarProgressView *view,
+ ThunarJob *job);
+void thunar_progress_view_set_icon_name (ThunarProgressView *view,
+ const gchar *icon_name);
+void thunar_progress_view_set_title (ThunarProgressView *view,
+ const gchar *title);
+
+G_END_DECLS;
+
+#endif /* !__THUNAR_PROGRESS_VIEW_H__ */
More information about the Xfce4-commits
mailing list