diff --git a/src/libsysprof/sysprof-document.c b/src/libsysprof/sysprof-document.c index 478606a5..bbe4c116 100644 --- a/src/libsysprof/sysprof-document.c +++ b/src/libsysprof/sysprof-document.c @@ -2581,3 +2581,69 @@ sysprof_document_list_dbus_messages (SysprofDocument *self) return _sysprof_document_bitset_index_new (G_LIST_MODEL (self), self->dbus_messages); } + +static void +sysprof_document_save_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GFile *file = (GFile *)object; + g_autoptr(GError) error = NULL; + g_autoptr(GTask) task = user_data; + + g_assert (G_IS_FILE (file)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (G_IS_TASK (task)); + + if (!g_file_replace_contents_finish (file, result, NULL, &error)) + g_task_return_error (task, g_steal_pointer (&error)); + else + g_task_return_boolean (task, TRUE); +} + +/** + * sysprof_document_save_async: + * @self: a #SysprofDocument + * @file: a #GFile + * @cancellable: (nullable): a #GCancellable or %NULL + * + */ +void +sysprof_document_save_async (SysprofDocument *self, + GFile *file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = NULL; + g_autoptr(GBytes) bytes = NULL; + + g_return_if_fail (SYSPROF_IS_DOCUMENT (self)); + g_return_if_fail (G_IS_FILE (file)); + g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, sysprof_document_save_async); + + bytes = g_mapped_file_get_bytes (self->mapped_file); + + g_file_replace_contents_bytes_async (file, + bytes, + NULL, + FALSE, + G_FILE_CREATE_REPLACE_DESTINATION, + cancellable, + sysprof_document_save_cb, + g_steal_pointer (&task)); +} + +gboolean +sysprof_document_save_finish (SysprofDocument *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (SYSPROF_IS_DOCUMENT (self), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} diff --git a/src/libsysprof/sysprof-document.h b/src/libsysprof/sysprof-document.h index 665a9d3a..87976d8e 100644 --- a/src/libsysprof/sysprof-document.h +++ b/src/libsysprof/sysprof-document.h @@ -120,5 +120,15 @@ SYSPROF_AVAILABLE_IN_ALL GBytes *sysprof_document_serialize_symbols_finish (SysprofDocument *self, GAsyncResult *result, GError **error); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_document_save_async (SysprofDocument *self, + GFile *file, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +SYSPROF_AVAILABLE_IN_ALL +gboolean sysprof_document_save_finish (SysprofDocument *self, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/src/sysprof/sysprof-window.c b/src/sysprof/sysprof-window.c index 237c4fe4..3c58bccb 100644 --- a/src/sysprof/sysprof-window.c +++ b/src/sysprof/sysprof-window.c @@ -308,6 +308,69 @@ sysprof_window_session_zoom_out (GtkWidget *widget, sysprof_session_zoom_to_selection (self->session); } +static void +sysprof_window_write_document_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + SysprofDocument *document = (SysprofDocument *)object; + g_autoptr(SysprofWindow) self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + + g_assert (SYSPROF_IS_DOCUMENT (document)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (SYSPROF_IS_WINDOW (self)); + + if (!sysprof_document_save_finish (document, result, &error)) + g_warning ("%s", error->message); +} + +static void +sysprof_window_save_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GtkFileDialog *dialog = (GtkFileDialog *)object; + g_autoptr(SysprofWindow) self = user_data; + g_autoptr(GError) error = NULL; + g_autoptr(GFile) file = NULL; + + g_assert (GTK_IS_FILE_DIALOG (dialog)); + g_assert (G_IS_ASYNC_RESULT (result)); + g_assert (SYSPROF_IS_WINDOW (self)); + + if ((file = gtk_file_dialog_save_finish (dialog, result, &error))) + sysprof_document_save_async (self->document, + file, + NULL, + sysprof_window_write_document_cb, + g_object_ref (self)); +} + +static void +sysprof_window_save_capture (GtkWidget *widget, + const char *action_name, + GVariant *param) +{ + SysprofWindow *self = (SysprofWindow *)widget; + g_autoptr(GtkFileDialog) dialog = NULL; + + g_assert (SYSPROF_IS_WINDOW (self)); + + dialog = gtk_file_dialog_new (); + gtk_file_dialog_set_title (dialog, _("Save to File")); + gtk_file_dialog_set_accept_label (dialog, _("Save")); + gtk_file_dialog_set_modal (dialog, TRUE); + gtk_file_dialog_set_initial_name (dialog, "capture.syscap"); + + gtk_file_dialog_save (dialog, + GTK_WINDOW (self), + NULL, + sysprof_window_save_cb, + g_object_ref (self)); +} + static void sysprof_window_dispose (GObject *object) { @@ -405,6 +468,7 @@ sysprof_window_class_init (SysprofWindowClass *klass) gtk_widget_class_install_action (widget_class, "session.zoom-in", NULL, sysprof_window_session_zoom_in); gtk_widget_class_install_action (widget_class, "session.seek-forward", NULL, sysprof_window_session_seek_forward); gtk_widget_class_install_action (widget_class, "session.seek-backward", NULL, sysprof_window_session_seek_backward); + gtk_widget_class_install_action (widget_class, "win.save-capture", NULL, sysprof_window_save_capture); gtk_widget_class_add_binding_action (widget_class, GDK_KEY_plus, GDK_CONTROL_MASK, "session.zoom-in", NULL); gtk_widget_class_add_binding_action (widget_class, GDK_KEY_equal, GDK_CONTROL_MASK, "session.zoom-in", NULL); diff --git a/src/sysprof/sysprof-window.ui b/src/sysprof/sysprof-window.ui index 98767d3f..3dca3682 100644 --- a/src/sysprof/sysprof-window.ui +++ b/src/sysprof/sysprof-window.ui @@ -32,6 +32,12 @@ action(win.open-capture) + + + <ctrl>s + action(win.save-capture) + + @@ -312,6 +318,7 @@ Save As… + win.save-capture