[libpanel] save-dialog: keep window alive during async operations
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpanel] save-dialog: keep window alive during async operations
- Date: Tue, 13 Sep 2022 22:22:59 +0000 (UTC)
commit 426064815cdb663bf573ea9bbefba0bbddb5819c
Author: Christian Hergert <chergert redhat com>
Date: Tue Sep 13 15:22:39 2022 -0700
save-dialog: keep window alive during async operations
Additionally, this allows the cancel operation to be used later so that
we can cancel the inflight save operations.
Some wizardry was necessary for the close_request since we'd get called
(and cancelled) vis the response signal before we can determine if the
operation is active.
src/panel-save-dialog.c | 92 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 76 insertions(+), 16 deletions(-)
---
diff --git a/src/panel-save-dialog.c b/src/panel-save-dialog.c
index eea4d85..7aa0685 100644
--- a/src/panel-save-dialog.c
+++ b/src/panel-save-dialog.c
@@ -31,11 +31,18 @@
struct _PanelSaveDialog
{
AdwMessageDialog parent_instance;
+
GPtrArray *rows;
+ GCancellable *cancellable;
+ GTask *task;
+
AdwPreferencesPage *page;
AdwPreferencesGroup *group;
- GTask *task;
+
guint close_after_save : 1;
+ guint discarding : 1;
+ guint saving : 1;
+ guint suppress_close : 1;
};
typedef struct
@@ -84,14 +91,13 @@ panel_save_dialog_response_cancel_cb (PanelSaveDialog *self,
g_assert (PANEL_IS_SAVE_DIALOG (self));
- task = g_steal_pointer (&self->task);
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_CANCELLED,
- "Operation was cancelled");
- gtk_window_destroy (GTK_WINDOW (self));
-
- g_clear_object (&task);
+ if ((task = g_steal_pointer (&self->task)))
+ {
+ g_cancellable_cancel (self->cancellable);
+ if (!g_task_get_completed (task))
+ g_task_return_error_if_cancelled (task);
+ g_clear_object (&task);
+ }
}
static void
@@ -102,6 +108,8 @@ panel_save_dialog_response_discard_cb (PanelSaveDialog *self,
g_assert (PANEL_IS_SAVE_DIALOG (self));
+ self->discarding = TRUE;
+
task = g_steal_pointer (&self->task);
for (guint i = 0; i < self->rows->len; i++)
@@ -112,9 +120,8 @@ panel_save_dialog_response_discard_cb (PanelSaveDialog *self,
panel_save_delegate_discard (delegate);
}
- g_task_return_boolean (task, TRUE);
-
- gtk_window_destroy (GTK_WINDOW (self));
+ if (!g_task_get_completed (task))
+ g_task_return_boolean (task, TRUE);
g_clear_object (&task);
}
@@ -142,7 +149,8 @@ panel_save_dialog_save_cb (GObject *object,
}
else if (save->close_after_save)
{
- panel_save_delegate_close (delegate);
+ if (!g_task_had_error (task))
+ panel_save_delegate_close (delegate);
}
g_ptr_array_remove (save->delegates, delegate);
@@ -169,6 +177,8 @@ panel_save_dialog_response_save_cb (PanelSaveDialog *self,
adw_message_dialog_set_response_enabled (ADW_MESSAGE_DIALOG (self), "save", FALSE);
adw_message_dialog_set_response_enabled (ADW_MESSAGE_DIALOG (self), "discard", FALSE);
+ self->saving = TRUE;
+
save = g_slice_new0 (Save);
save->close_after_save = self->close_after_save;
save->delegates = g_ptr_array_new_with_free_func (g_object_unref);
@@ -240,12 +250,47 @@ set_response_visible (AdwMessageDialog *dialog,
find_button_and_set_visible (GTK_WIDGET (narrow), label, visible);
}
+static gboolean
+panel_save_dialog_close_request_idle_cb (gpointer user_data)
+{
+ PanelSaveDialog *self = user_data;
+
+ g_assert (PANEL_IS_SAVE_DIALOG (self));
+
+ if (self->saving || self->discarding)
+ return G_SOURCE_REMOVE;
+
+ if (!GTK_WINDOW_CLASS (panel_save_dialog_parent_class)->close_request (GTK_WINDOW (self)))
+ gtk_window_destroy (GTK_WINDOW (self));
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+panel_save_dialog_close_request (GtkWindow *window)
+{
+ PanelSaveDialog *self = (PanelSaveDialog *)window;
+
+ g_assert (PANEL_IS_SAVE_DIALOG (self));
+
+ /* Defer to idle so that we can check if we are actively saving. */
+ if (self->suppress_close)
+ g_idle_add_full (G_PRIORITY_HIGH,
+ panel_save_dialog_close_request_idle_cb,
+ g_object_ref (self),
+ g_object_unref);
+
+ return TRUE;
+}
+
static void
panel_save_dialog_dispose (GObject *object)
{
PanelSaveDialog *self = (PanelSaveDialog *)object;
g_clear_pointer (&self->rows, g_ptr_array_unref);
+ g_clear_object (&self->cancellable);
+ g_clear_object (&self->task);
G_OBJECT_CLASS (panel_save_dialog_parent_class)->dispose (object);
}
@@ -293,11 +338,14 @@ panel_save_dialog_class_init (PanelSaveDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
object_class->dispose = panel_save_dialog_dispose;
object_class->get_property = panel_save_dialog_get_property;
object_class->set_property = panel_save_dialog_set_property;
+ window_class->close_request = panel_save_dialog_close_request;
+
/**
* PanelSaveDialog:close-after-save:
*
@@ -326,6 +374,7 @@ static void
panel_save_dialog_init (PanelSaveDialog *self)
{
self->rows = g_ptr_array_new ();
+ self->suppress_close = TRUE;
gtk_widget_init_template (GTK_WIDGET (self));
}
@@ -454,6 +503,8 @@ panel_save_dialog_add_delegate (PanelSaveDialog *self,
g_return_if_fail (PANEL_IS_SAVE_DIALOG (self));
g_return_if_fail (PANEL_IS_SAVE_DELEGATE (delegate));
+ panel_save_delegate_set_progress (delegate, 0);
+
row = panel_save_dialog_row_new (delegate);
g_signal_connect_object (row,
"notify::selected",
@@ -474,8 +525,13 @@ task_completed_cb (PanelSaveDialog *self,
g_assert (PANEL_IS_SAVE_DIALOG (self));
g_assert (G_IS_TASK (task));
+ self->saving = FALSE;
+ self->discarding = FALSE;
+
if (self->task == task)
g_clear_object (&self->task);
+
+ gtk_window_destroy (GTK_WINDOW (self));
}
void
@@ -491,18 +547,22 @@ panel_save_dialog_run_async (PanelSaveDialog *self,
g_object_ref_sink (self);
- task = g_task_new (self, cancellable, callback, user_data);
+ if (cancellable == NULL)
+ self->cancellable = g_cancellable_new ();
+ else
+ self->cancellable = g_object_ref (cancellable);
+
+ task = g_task_new (self, self->cancellable, callback, user_data);
g_task_set_source_tag (task, panel_save_dialog_run_async);
g_signal_connect_object (task,
- "notify::complete",
+ "notify::completed",
G_CALLBACK (task_completed_cb),
self,
G_CONNECT_SWAPPED);
if (self->rows->len == 0)
{
- gtk_window_destroy (GTK_WINDOW (self));
g_task_return_boolean (task, TRUE);
g_clear_object (&task);
return;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]