Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
bustle
bustle
Commits
a1b13fb1
Verified
Commit
a1b13fb1
authored
Mar 29, 2019
by
Will Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement recording
parent
f2f34a4e
Pipeline
#27433
passed with stage
in 4 minutes and 20 seconds
Changes
8
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
555 additions
and
41 deletions
+555
-41
c-sources/bustle-record-address-dialog.c
c-sources/bustle-record-address-dialog.c
+120
-0
c-sources/bustle-record-address-dialog.h
c-sources/bustle-record-address-dialog.h
+22
-0
c-sources/bustle-record-address-dialog.ui
c-sources/bustle-record-address-dialog.ui
+108
-0
c-sources/bustle-viewer.c
c-sources/bustle-viewer.c
+3
-4
c-sources/bustle-window.c
c-sources/bustle-window.c
+296
-35
c-sources/bustle-window.h
c-sources/bustle-window.h
+3
-2
c-sources/bustle.gresource.xml
c-sources/bustle.gresource.xml
+1
-0
c-sources/meson.build
c-sources/meson.build
+2
-0
No files found.
c-sources/bustle-record-address-dialog.c
0 → 100644
View file @
a1b13fb1
#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
);
}
c-sources/bustle-record-address-dialog.h
0 → 100644
View file @
a1b13fb1
#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
c-sources/bustle-record-address-dialog.ui
0 → 100644
View file @
a1b13fb1
<?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>
c-sources/bustle-viewer.c
View file @
a1b13fb1
...
...
@@ -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
...
...
c-sources/bustle-window.c
View file @
a1b13fb1
...
...
@@ -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
,
&
timestamp_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
(
mod
el
,
ts
,
message
);
bustle_
window
_add_message
(
s
el
f
,
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.p