diff options
author | Will Thompson <will@willthompson.co.uk> | 2019-03-29 08:30:04 +0000 |
---|---|---|
committer | Will Thompson <will@willthompson.co.uk> | 2019-03-31 21:37:31 +0100 |
commit | a1b13fb1c873c75daeb2e15fc323fa3db3217026 (patch) | |
tree | 634425f6419e3e7a8f0bd50b573e857c5e5c374b | |
parent | f2f34a4e7d7d87fdf4d1079463f8d15a59cc3501 (diff) |
Implement recordingstaging/c
-rw-r--r-- | c-sources/bustle-record-address-dialog.c | 120 | ||||
-rw-r--r-- | c-sources/bustle-record-address-dialog.h | 22 | ||||
-rw-r--r-- | c-sources/bustle-record-address-dialog.ui | 108 | ||||
-rw-r--r-- | c-sources/bustle-viewer.c | 7 | ||||
-rw-r--r-- | c-sources/bustle-window.c | 331 | ||||
-rw-r--r-- | c-sources/bustle-window.h | 5 | ||||
-rw-r--r-- | c-sources/bustle.gresource.xml | 1 | ||||
-rw-r--r-- | c-sources/meson.build | 2 |
8 files changed, 555 insertions, 41 deletions
diff --git a/c-sources/bustle-record-address-dialog.c b/c-sources/bustle-record-address-dialog.c new file mode 100644 index 0000000..0b77428 --- /dev/null +++ b/c-sources/bustle-record-address-dialog.c @@ -0,0 +1,120 @@ +#include "bustle-record-address-dialog.h" + +struct _BustleRecordAddressDialog +{ + GtkDialog parent_instance; + + GtkEntry *recordAddressEntry; + GtkButton *recordAddressRecord; +}; + +G_DEFINE_TYPE (BustleRecordAddressDialog, bustle_record_address_dialog, GTK_TYPE_DIALOG) + +BustleRecordAddressDialog * +bustle_record_address_dialog_new (GtkWindow *parent) +{ + return g_object_new (BUSTLE_TYPE_RECORD_ADDRESS_DIALOG, + "transient-for", parent, + NULL); +} + +static void +bustle_record_address_dialog_finalize (GObject *object) +{ + BustleRecordAddressDialog *self = (BustleRecordAddressDialog *)object; + + g_debug ("%s: %p", G_STRFUNC, self); + + G_OBJECT_CLASS (bustle_record_address_dialog_parent_class)->finalize (object); +} + +static void +bustle_record_address_dialog_class_init (BustleRecordAddressDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = bustle_record_address_dialog_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, + "/org/freedesktop/Bustle/bustle-record-address-dialog.ui"); + gtk_widget_class_bind_template_child (widget_class, BustleRecordAddressDialog, recordAddressEntry); + gtk_widget_class_bind_template_child (widget_class, BustleRecordAddressDialog, recordAddressRecord); +} + +static void +entry_changed_cb (GtkEditable *editable, + gpointer user_data) +{ + BustleRecordAddressDialog *self = BUSTLE_RECORD_ADDRESS_DIALOG (user_data); + GtkEntry *entry = GTK_ENTRY (editable); + const gchar *text = gtk_entry_get_text (entry); + g_autoptr(GError) local_error = NULL; + gboolean ok = text && *text && g_dbus_is_supported_address (text, &local_error); + + gtk_widget_set_sensitive (GTK_WIDGET (self->recordAddressRecord), ok); + if (ok) + { + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL); + } + else if (text && *text) + { + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); + gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, local_error->message); + } +} + +static void +bustle_record_address_dialog_init (BustleRecordAddressDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + g_signal_connect_object (self->recordAddressEntry, "changed", + G_CALLBACK (entry_changed_cb), self, 0); + entry_changed_cb (GTK_EDITABLE (self->recordAddressEntry), self); +} + +static void +response_cb (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + BustleRecordAddressDialog *self = BUSTLE_RECORD_ADDRESS_DIALOG (dialog); + g_autoptr(GTask) task = G_TASK (user_data); + + if (response_id == GTK_RESPONSE_ACCEPT) + g_task_return_pointer (task, + g_strdup (gtk_entry_get_text (self->recordAddressEntry)), + g_free); + else + g_cancellable_cancel (g_task_get_cancellable (task)); + + g_signal_handlers_disconnect_by_data (dialog, task); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + + +void +bustle_record_address_dialog_run_async (BustleRecordAddressDialog *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr(GTask) task = g_task_new (self, cancellable, callback, user_data); + + g_signal_connect (self, "response", + G_CALLBACK (response_cb), g_steal_pointer (&task)); + gtk_widget_show_all (GTK_WIDGET (self)); +} + +gchar * +bustle_record_address_dialog_run_finish (BustleRecordAddressDialog *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (BUSTLE_IS_RECORD_ADDRESS_DIALOG (self), NULL); + g_return_val_if_fail (g_task_is_valid (result, self), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} diff --git a/c-sources/bustle-record-address-dialog.h b/c-sources/bustle-record-address-dialog.h new file mode 100644 index 0000000..9c02382 --- /dev/null +++ b/c-sources/bustle-record-address-dialog.h @@ -0,0 +1,22 @@ +#pragma once + +#include <gtk/gtk.h> + +G_BEGIN_DECLS + +#define BUSTLE_TYPE_RECORD_ADDRESS_DIALOG (bustle_record_address_dialog_get_type()) + +G_DECLARE_FINAL_TYPE (BustleRecordAddressDialog, bustle_record_address_dialog, BUSTLE, RECORD_ADDRESS_DIALOG, GtkDialog) + +BustleRecordAddressDialog *bustle_record_address_dialog_new (GtkWindow *parent); +void bustle_record_address_dialog_run_async (BustleRecordAddressDialog *self, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gchar *bustle_record_address_dialog_run_finish (BustleRecordAddressDialog *self, + GAsyncResult *result, + GError **error); + + + +G_END_DECLS diff --git a/c-sources/bustle-record-address-dialog.ui b/c-sources/bustle-record-address-dialog.ui new file mode 100644 index 0000000..7215e9d --- /dev/null +++ b/c-sources/bustle-record-address-dialog.ui @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <template class="BustleRecordAddressDialog" parent="GtkDialog"> + <property name="title" translatable="yes">Record Address</property> + <property name="can_focus">False</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="recordAddressCancel"> + <property name="label">gtk-cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_stock">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="recordAddressRecord"> + <property name="label" translatable="yes">_Record</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_left">6</property> + <property name="margin_right">6</property> + <property name="margin_top">6</property> + <property name="margin_bottom">6</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Address:</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="recordAddressEntry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="has_focus">True</property> + <property name="activates_default">True</property> + <property name="width_chars">60</property> + <property name="placeholder_text" translatable="yes" comments="Just translate the "e.g."; leave the rest untouched.">e.g. unix:abstract=/tmp/dbus-E5RlEB5Tzu,guid= b1c1921b62283b7b612b57305b20cc28</property> + <property name="input_hints">GTK_INPUT_HINT_NO_SPELLCHECK | GTK_INPUT_HINT_NO_EMOJI | GTK_INPUT_HINT_NONE</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-6">recordAddressCancel</action-widget> + <action-widget response="-3">recordAddressRecord</action-widget> + </action-widgets> + </template> +</interface> diff --git a/c-sources/bustle-viewer.c b/c-sources/bustle-viewer.c index 4ae4264..c8c8e2f 100644 --- a/c-sources/bustle-viewer.c +++ b/c-sources/bustle-viewer.c @@ -11,7 +11,8 @@ open_cb (GApplication *application, { for (int i = 0; i < n_files; i++) { - bustle_window_new (GTK_APPLICATION (application), files[i]); + BustleWindow *window = bustle_window_new (GTK_APPLICATION (application)); + bustle_window_load_file (window, files[i]); } } @@ -19,9 +20,7 @@ static void activate_cb (GApplication *application, gpointer user_data) { - g_autoptr(GFile) file = g_file_new_for_path ("/home/wjt/src/bustle/oh-no.pcap"); - - bustle_window_new (GTK_APPLICATION (application), file); + bustle_window_new (GTK_APPLICATION (application)); } gint diff --git a/c-sources/bustle-window.c b/c-sources/bustle-window.c index 36d53b0..71eae0d 100644 --- a/c-sources/bustle-window.c +++ b/c-sources/bustle-window.c @@ -6,20 +6,41 @@ #include "bustle-model.h" #include "bustle-name-model.h" #include "bustle-pcap-reader.h" +#include "bustle-record-address-dialog.h" +#include "pcap-monitor.h" struct _BustleWindow { GtkApplicationWindow parent_instance; GFile *file; + BustlePcapMonitor *monitor; + + BustleModel *model; + guint messages_logged; + /* Timestamp of the first message in @model, or 0 if it is empty. */ + gint64 first_ts; GtkStack *diagramOrNot; GtkScrolledWindow *diagramScrolledWindow; + /* Error stuff */ GtkInfoBar *errorBar; GtkLabel *errorBarTitle; GtkLabel *errorBarDetails; + /* Menu stuff */ + GtkMenuButton *headerRecord; + GtkMenuButton *headerStop; + /* TODO: move to actions */ + GtkMenuItem *recordSession; + GtkMenuItem *recordSystem; + GtkMenuItem *recordAddress; + + GtkSpinner *headerSpinner; + GtkLabel *headerTitle; + GtkLabel *headerSubtitle; + /* Details stuff */ /* TODO: move to separate widget */ GtkGrid *detailsGrid; @@ -38,11 +59,15 @@ struct _BustleWindow G_DEFINE_TYPE (BustleWindow, bustle_window, GTK_TYPE_APPLICATION_WINDOW) +static void bustle_window_show_model (BustleWindow *self); static void bustle_window_show_error (BustleWindow *self, const gchar *title, const GError *error); -static gboolean bustle_window_load_file (BustleWindow *self, - GError **error); + +static void record_cb (GtkMenuItem *item, + gpointer user_data); +static void stop_cb (GtkButton *item, + gpointer user_data); typedef enum { PROP_FILE = 1, @@ -52,15 +77,12 @@ typedef enum { static GParamSpec *properties [N_PROPS]; BustleWindow * -bustle_window_new (GtkApplication *application, - GFile *file) +bustle_window_new (GtkApplication *application) { g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL); - g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL); return g_object_new (BUSTLE_TYPE_WINDOW, "application", application, - "file", file, NULL); } @@ -76,24 +98,22 @@ static void bustle_window_constructed (GObject *object) { BustleWindow *self = (BustleWindow *)object; - g_autoptr(GError) error = NULL; G_OBJECT_CLASS (bustle_window_parent_class)->constructed (object); - gtk_widget_show (GTK_WIDGET (self)); + self->model = bustle_model_new (); + bustle_window_show_model (self); g_signal_connect_object (self->errorBar, "response", G_CALLBACK (error_bar_response_cb), self, 0); - g_assert (self->file != NULL); - if (!bustle_window_load_file (self, &error)) - { - g_autofree gchar *title = g_strdup_printf (_("Could not read ‘%s’."), - g_file_peek_path (self->file)); + g_signal_connect (self->recordSession, "activate", G_CALLBACK (record_cb), self); + g_signal_connect (self->recordSystem, "activate", G_CALLBACK (record_cb), self); + g_signal_connect (self->recordAddress, "activate", G_CALLBACK (record_cb), self); + g_signal_connect (self->headerStop, "clicked", G_CALLBACK (stop_cb), self); - bustle_window_show_error (self, title, error); - } + gtk_widget_show (GTK_WIDGET (self)); } static void @@ -102,6 +122,8 @@ bustle_window_finalize (GObject *object) BustleWindow *self = (BustleWindow *)object; g_clear_object (&self->file); + g_clear_object (&self->monitor); + g_clear_object (&self->model); G_OBJECT_CLASS (bustle_window_parent_class)->finalize (object); } @@ -162,8 +184,7 @@ bustle_window_class_init (BustleWindowClass *klass) "File", "File", G_TYPE_FILE, - (G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | + (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_FILE, properties [PROP_FILE]); @@ -177,6 +198,16 @@ bustle_window_class_init (BustleWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, BustleWindow, errorBarTitle); gtk_widget_class_bind_template_child (widget_class, BustleWindow, errorBarDetails); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, headerRecord); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, headerStop); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, recordSession); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, recordSystem); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, recordAddress); + + gtk_widget_class_bind_template_child (widget_class, BustleWindow, headerSpinner); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, headerTitle); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, headerSubtitle); + gtk_widget_class_bind_template_child (widget_class, BustleWindow, detailsGrid); gtk_widget_class_bind_template_child (widget_class, BustleWindow, detailsType); gtk_widget_class_bind_template_child (widget_class, BustleWindow, detailsSender); @@ -204,14 +235,14 @@ timestamp_data_func (GtkTreeViewColumn *tree_column, GtkTreeIter *iter, gpointer data) { - gint64 *first_ts = data; + BustleWindow *self = BUSTLE_WINDOW (data); gint64 timestamp_usec; g_autofree gchar *text = NULL; gtk_tree_model_get (tree_model, iter, BUSTLE_MODEL_COLUMN_TIMESTAMP_USEC, ×tamp_usec, -1); - text = g_strdup_printf ("%.3fs", (double) (timestamp_usec - *first_ts) / G_USEC_PER_SEC); + text = g_strdup_printf ("+%.3fs", (double) (timestamp_usec - self->first_ts) / G_USEC_PER_SEC); g_object_set (cell, "text", text, NULL); } @@ -494,16 +525,12 @@ selection_changed_cb (GtkTreeSelection *selection, } static void -bustle_window_show_model (BustleWindow *self, - GtkTreeModel *model) +bustle_window_show_model (BustleWindow *self) { - g_autoptr(GtkTreePath) path = gtk_tree_path_new_from_string ("0"); - GtkTreeIter iter; - gint64 *first_ts = g_new (gint64, 1); - - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_model_get (model, &iter, BUSTLE_MODEL_COLUMN_TIMESTAMP_USEC, first_ts, -1); + /* + */ + GtkTreeModel *model = bustle_model_get_tree_model (self->model); GtkWidget *tree_view = gtk_tree_view_new_with_model (model); GtkCellRenderer *renderer; GtkTreeViewColumn *column; @@ -519,7 +546,7 @@ bustle_window_show_model (BustleWindow *self, column = gtk_tree_view_column_new_with_attributes ("Timestamp", renderer, NULL); gtk_tree_view_column_set_cell_data_func (column, renderer, timestamp_data_func, - g_steal_pointer (&first_ts), g_free); + self, NULL); gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); renderer = gtk_cell_renderer_text_new (); @@ -559,13 +586,26 @@ bustle_window_show_model (BustleWindow *self, selection_changed_cb (selection, self); gtk_container_add (GTK_CONTAINER (self->diagramScrolledWindow), tree_view); - gtk_stack_set_visible_child_name (self->diagramOrNot, "CanvasPage"); gtk_widget_show (tree_view); } +static void +bustle_window_add_message (BustleWindow *self, + gint64 ts, + GDBusMessage *message) +{ + if (self->first_ts == 0) + { + self->first_ts = ts; + gtk_stack_set_visible_child_name (self->diagramOrNot, "CanvasPage"); + } + + bustle_model_add_message (self->model, ts, message); +} + static gboolean -bustle_window_load_file (BustleWindow *self, - GError **error) +bustle_window_do_load_file (BustleWindow *self, + GError **error) { g_assert (self->file != NULL); @@ -574,8 +614,6 @@ bustle_window_load_file (BustleWindow *self, if (reader == NULL) return FALSE; - g_autoptr(BustleModel) model = bustle_model_new (); - gint64 ts; g_autoptr(GDBusMessage) message = NULL; @@ -584,11 +622,10 @@ bustle_window_load_file (BustleWindow *self, if (message == NULL) { /* EOF */ - bustle_window_show_model (self, bustle_model_get_tree_model (model)); return TRUE; } - bustle_model_add_message (model, ts, message); + bustle_window_add_message (self, ts, message); } return FALSE; @@ -615,3 +652,227 @@ bustle_window_show_error (BustleWindow *self, /* TODO: use :revealed, modulo https://gitlab.gnome.org/GNOME/gtk/issues/1165 */ gtk_widget_show (GTK_WIDGET (self->errorBar)); } + +void +bustle_window_load_file (BustleWindow *self, + GFile *file) +{ + g_return_if_fail (BUSTLE_IS_WINDOW (self)); + g_return_if_fail (G_IS_FILE (file)); + + g_return_if_fail (self->file == NULL); + self->file = g_object_ref (file); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]); + + g_autoptr(GError) local_error = NULL; + + if (!bustle_window_do_load_file (self, &local_error)) + { + g_autofree gchar *title = g_strdup_printf (_("Could not read ‘%s’."), + g_file_peek_path (self->file)); + bustle_window_show_error (self, title, local_error); + } +} + +static void +message_logged_cb (BustlePcapMonitor *monitor, + long timestamp_sec, + long timestamp_usec, + const guint8 *blob, + gsize len, + gpointer user_data) +{ + BustleWindow *self = BUSTLE_WINDOW (user_data); + gint64 timestamp = G_USEC_PER_SEC * timestamp_sec + timestamp_usec; + g_autoptr(GError) local_error = NULL; + g_autoptr(GDBusMessage) message = NULL; + + message = g_dbus_message_new_from_blob ((guchar *) blob, len, + G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING, + &local_error); + if (message == NULL) + { + bustle_window_show_error (self, + _("Could not decode recorded message."), + local_error); + bustle_pcap_monitor_stop (self->monitor); + } + else + { + bustle_window_add_message (self, timestamp, message); + self->messages_logged++; + + g_autofree gchar *subtitle = g_strdup_printf (_("%u messages"), + self->messages_logged); + gtk_label_set_text (self->headerSubtitle, subtitle); + } +} + +static void +stopped_cb (BustlePcapMonitor *monitor, + guint domain, + gint code, + const gchar *message, + gpointer user_data) +{ + BustleWindow *self = BUSTLE_WINDOW (user_data); + g_assert (domain != 0); + g_assert (domain <= G_MAXUINT32); + g_autoptr(GError) local_error = g_error_new_literal ((GQuark) domain, code, message); + + gtk_spinner_stop (self->headerSpinner); + gtk_widget_show (GTK_WIDGET (self->headerRecord)); + gtk_widget_hide (GTK_WIDGET (self->headerStop)); + if (self->first_ts == 0) + { + gtk_stack_set_visible_child_name (self->diagramOrNot, "InstructionsPage"); + g_clear_object (&self->file); + } + + if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + bustle_window_show_error (self, + _("Recording failed."), + local_error); + + g_signal_handlers_disconnect_by_data (self->monitor, self); + g_clear_object (&self->monitor); +} + +static void +bustle_window_start_recording (BustleWindow *self, + GBusType bus_type, + const gchar *address) +{ + g_assert (BUSTLE_IS_WINDOW (self)); + g_assert ((bus_type == G_BUS_TYPE_NONE) == (address != NULL)); + g_assert (self->file == NULL); + g_assert (self->monitor == NULL); + + g_autoptr(GDateTime) now = g_date_time_new_now_local (); + g_autofree gchar *basename = g_date_time_format (now, + "%F %H-%M-%S.pcap"); + g_autofree gchar *target_path = g_build_filename (g_get_user_cache_dir (), + "bustle", + basename, + NULL); + g_autoptr(GFile) target_file = g_file_new_for_path (target_path); + g_autoptr(GFile) target_dir = g_file_get_parent (target_file); + g_autoptr(GError) local_error = NULL; + + if (!g_file_make_directory_with_parents (target_dir, NULL, &local_error) && + !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS)) + { + bustle_window_show_error (self, + _("Could not start recording."), + local_error); + return; + } + + g_clear_error (&local_error); + self->monitor = bustle_pcap_monitor_new (bus_type, address, target_path, + &local_error); + if (self->monitor == NULL) + { + bustle_window_show_error (self, + _("Could not start recording."), + local_error); + } + else + { + g_autofree gchar *title_to_free = NULL; + const gchar *title = NULL; + switch (bus_type) + { + case G_BUS_TYPE_SESSION: + title = _("Recording session bus…"); + break; + case G_BUS_TYPE_SYSTEM: + title = _("Recording system bus…"); + break; + case G_BUS_TYPE_NONE: + title_to_free = g_strdup_printf (_("Recording %s…"), address); + title = title_to_free; + break; + default: + g_assert_not_reached (); + } + + g_set_object (&self->file, target_file); + + gtk_stack_set_visible_child_name (self->diagramOrNot, "PleaseHoldPage"); + + gtk_spinner_start (self->headerSpinner); + gtk_label_set_text (self->headerTitle, title); + + gtk_widget_hide (GTK_WIDGET (self->headerRecord)); + gtk_widget_show (GTK_WIDGET (self->headerStop)); + + g_signal_connect_object (self->monitor, "message-logged", + G_CALLBACK (message_logged_cb), self, 0); + g_signal_connect_object (self->monitor, "stopped", + G_CALLBACK (stopped_cb), self, 0); + } +} + +static void +bustle_window_start_recording_somewhere (BustleWindow *self, + GBusType bus_type, + const gchar *address) +{ + BustleWindow *target; + + if (self->first_ts != 0) + target = bustle_window_new (gtk_window_get_application (GTK_WINDOW (self))); + else + target = self; + + bustle_window_start_recording (target, bus_type, address); +} + +static void +record_address_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr(BustleWindow) self = BUSTLE_WINDOW (user_data); + g_autoptr(GError) local_error = NULL; + g_autofree gchar *address = NULL; + + address = bustle_record_address_dialog_run_finish (BUSTLE_RECORD_ADDRESS_DIALOG (source), + result, + &local_error); + if (address != NULL) + bustle_window_start_recording_somewhere (self, G_BUS_TYPE_NONE, address); + else if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("%s", local_error->message); +} + +static void +record_cb (GtkMenuItem *item, + gpointer user_data) +{ + BustleWindow *self = BUSTLE_WINDOW (user_data); + + if (self->recordSession == item) + bustle_window_start_recording_somewhere (self, G_BUS_TYPE_SESSION, NULL); + else if (self->recordSystem == item) + bustle_window_start_recording_somewhere (self, G_BUS_TYPE_SYSTEM, NULL); + else if (self->recordAddress == item) + { + BustleRecordAddressDialog *d = bustle_record_address_dialog_new (GTK_WINDOW (self)); + bustle_record_address_dialog_run_async (d, NULL, record_address_cb, g_object_ref (self)); + } + else + g_assert_not_reached (); +} + +static void +stop_cb (GtkButton *item, + gpointer user_data) +{ + BustleWindow *self = BUSTLE_WINDOW (user_data); + + g_assert (self->monitor != NULL); + + bustle_pcap_monitor_stop (self->monitor); +} diff --git a/c-sources/bustle-window.h b/c-sources/bustle-window.h index 39f5960..dd2cec3 100644 --- a/c-sources/bustle-window.h +++ b/c-sources/bustle-window.h @@ -8,7 +8,8 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (BustleWindow, bustle_window, BUSTLE, WINDOW, GtkApplicationWindow) -BustleWindow *bustle_window_new (GtkApplication *application, - GFile *file); +BustleWindow *bustle_window_new (GtkApplication *application); +void bustle_window_load_file (BustleWindow *self, + GFile *file); G_END_DECLS diff --git a/c-sources/bustle.gresource.xml b/c-sources/bustle.gresource.xml index 7287aa9..e729669 100644 --- a/c-sources/bustle.gresource.xml +++ b/c-sources/bustle.gresource.xml @@ -2,6 +2,7 @@ <gresources> <gresource prefix="/org/freedesktop/Bustle"> <file preprocess="xml-stripblanks">bustle-window.ui</file> + <file preprocess="xml-stripblanks">bustle-record-address-dialog.ui</file> </gresource> </gresources> diff --git a/c-sources/meson.build b/c-sources/meson.build index 9a6c889..2e0da04 100644 --- a/c-sources/meson.build +++ b/c-sources/meson.build @@ -49,6 +49,8 @@ bustle_sources = [ 'bustle-viewer.c', 'bustle-pcap-reader.c', 'bustle-pcap-reader.h', + 'bustle-record-address-dialog.c', + 'bustle-record-address-dialog.h', bustle_resources, ] |