Merge branch 'matthiasc/for-main' into 'main'

inspector: Add event traces

See merge request GNOME/gtk!7627
This commit is contained in:
Matthias Clasen
2024-08-18 21:00:01 +00:00
11 changed files with 256 additions and 25 deletions

View File

@@ -1205,6 +1205,19 @@ node_editor_window_add_renderer (NodeEditorWindow *self,
g_object_unref (paintable);
}
static void
update_paste_action (GdkClipboard *clipboard,
GParamSpec *pspec,
gpointer data)
{
GtkWidget *widget = GTK_WIDGET (data);
gboolean has_node;
has_node = gdk_content_formats_contain_mime_type (gdk_clipboard_get_formats (clipboard), "application/x-gtk-render-node");
gtk_widget_action_set_enabled (widget, "paste-node", has_node);
}
static void
node_editor_window_realize (GtkWidget *widget)
{
@@ -1242,6 +1255,7 @@ node_editor_window_realize (GtkWidget *widget)
self->after_paint_handler = g_signal_connect (frameclock, "after-paint",
G_CALLBACK (after_paint), self);
g_signal_connect (gtk_widget_get_clipboard (widget), "notify::formats", G_CALLBACK (update_paste_action), widget);
}
static void
@@ -1251,6 +1265,8 @@ node_editor_window_unrealize (GtkWidget *widget)
GdkFrameClock *frameclock;
guint i;
g_signal_handlers_disconnect_by_func (gtk_widget_get_clipboard (widget), update_paste_action, widget);
frameclock = gtk_widget_get_frame_clock (widget);
g_signal_handler_disconnect (frameclock, self->after_paint_handler);
self->after_paint_handler = 0;
@@ -1615,6 +1631,19 @@ edit_action_cb (GtkWidget *widget,
node_editor_window_edit (self, &start);
}
static void
paste_node_cb (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
NodeEditorWindow *self = NODE_EDITOR_WINDOW (widget);
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self->text_view));
gtk_text_buffer_set_text (buffer, "", 0);
gtk_text_buffer_paste_clipboard (buffer, gtk_widget_get_clipboard (widget), NULL, TRUE);
}
static void
node_editor_window_set_property (GObject *object,
guint prop_id,
@@ -1727,6 +1756,13 @@ node_editor_window_class_init (NodeEditorWindowClass *class)
action = gtk_named_action_new ("smart-edit");
shortcut = gtk_shortcut_new (trigger, action);
gtk_widget_class_add_shortcut (widget_class, shortcut);
gtk_widget_class_install_action (widget_class, "paste-node", NULL, paste_node_cb);
trigger = gtk_keyval_trigger_new (GDK_KEY_v, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
action = gtk_named_action_new ("paste-node");
shortcut = gtk_shortcut_new (trigger, action);
gtk_widget_class_add_shortcut (widget_class, shortcut);
}
static GtkWidget *

View File

@@ -22,6 +22,10 @@
</menu>
<menu id="extra_menu">
<section>
<item>
<attribute name="label" translatable="yes">Paste _Node</attribute>
<attribute name="action">paste-node</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Assisted _Edit</attribute>
<attribute name="action">smart-edit</attribute>

View File

@@ -494,7 +494,7 @@ gdk_registry_handle_global (void *data,
&server_decoration_listener,
display_wayland);
}
else if (strcmp(interface, "zxdg_output_manager_v1") == 0)
else if (strcmp (interface, "zxdg_output_manager_v1") == 0)
{
display_wayland->xdg_output_manager =
wl_registry_bind (display_wayland->wl_registry, id,
@@ -503,7 +503,7 @@ gdk_registry_handle_global (void *data,
gdk_wayland_display_init_xdg_output (display_wayland);
_gdk_wayland_display_async_roundtrip (display_wayland);
}
else if (strcmp(interface, "zwp_idle_inhibit_manager_v1") == 0)
else if (strcmp (interface, "zwp_idle_inhibit_manager_v1") == 0)
{
display_wayland->idle_inhibit_manager =
wl_registry_bind (display_wayland->wl_registry, id,

View File

@@ -1926,7 +1926,7 @@ gtk_propagate_event_internal (GtkWidget *widget,
i--;
}
/* If not yet handled, also propagate down */
/* If not yet handled, also propagate back up */
if (!handled_event)
{
/* Propagate event up the widget tree so that

View File

@@ -4586,6 +4586,8 @@ gtk_widget_run_controllers (GtkWidget *widget,
is_gesture = GTK_IS_GESTURE (controller);
this_handled = gtk_event_controller_handle_event (controller, event, target, x, y);
gtk_inspector_trace_event (event, phase, widget, controller, target, this_handled);
if (GTK_DEBUG_CHECK (KEYBINDINGS))
{
GdkEventType type = gdk_event_get_event_type (event);

View File

@@ -28,6 +28,7 @@ gtk_inspector_event_recording_finalize (GObject *object)
GtkInspectorEventRecording *recording = GTK_INSPECTOR_EVENT_RECORDING (object);
g_clear_pointer (&recording->event, gdk_event_unref);
g_array_unref (recording->traces);
G_OBJECT_CLASS (gtk_inspector_event_recording_parent_class)->finalize (object);
}
@@ -56,6 +57,7 @@ gtk_inspector_event_recording_new (gint64 timestamp,
NULL);
recording->event = gdk_event_ref (event);
recording->traces = g_array_new (FALSE, FALSE, sizeof (EventTrace));
return GTK_INSPECTOR_RECORDING (recording);
}
@@ -66,4 +68,34 @@ gtk_inspector_event_recording_get_event (GtkInspectorEventRecording *recording)
return recording->event;
}
void
gtk_inspector_event_recording_add_trace (GtkInspectorEventRecording *recording,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled)
{
EventTrace trace;
trace.phase = phase;
trace.widget = widget;
trace.widget_type = G_OBJECT_TYPE (widget);
trace.controller_type = G_OBJECT_TYPE (controller);
trace.target_type = G_OBJECT_TYPE (target);
trace.handled = handled;
g_array_append_val (recording->traces, trace);
}
EventTrace *
gtk_inspector_event_recording_get_traces (GtkInspectorEventRecording *recording,
gsize *n_traces)
{
*n_traces = recording->traces->len;
return (EventTrace *) recording->traces->data;
}
// vim: set et sw=2 ts=2:

View File

@@ -20,6 +20,9 @@
#include <gdk/gdk.h>
#include <gsk/gsk.h>
#include "gsk/gskprofilerprivate.h"
#include "gtk/gtkenums.h"
#include "gtk/gtkwidget.h"
#include "gtk/gtkeventcontroller.h"
#include "inspector/recording.h"
@@ -35,11 +38,22 @@ G_BEGIN_DECLS
typedef struct _GtkInspectorEventRecordingPrivate GtkInspectorEventRecordingPrivate;
typedef struct
{
GtkPropagationPhase phase;
gpointer widget;
GType widget_type;
GType controller_type;
GType target_type;
gboolean handled;
} EventTrace;
typedef struct _GtkInspectorEventRecording
{
GtkInspectorRecording parent;
GdkEvent *event;
GArray *traces;
} GtkInspectorEventRecording;
typedef struct _GtkInspectorEventRecordingClass
@@ -55,6 +69,15 @@ GtkInspectorRecording *
GdkEvent * gtk_inspector_event_recording_get_event (GtkInspectorEventRecording *recording);
void gtk_inspector_event_recording_add_trace (GtkInspectorEventRecording *recording,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled);
EventTrace * gtk_inspector_event_recording_get_traces (GtkInspectorEventRecording *recording,
gsize *n_traces);
G_END_DECLS

View File

@@ -212,8 +212,12 @@ struct _GtkInspectorRecorder
gboolean debug_nodes;
gboolean highlight_sequences;
gboolean record_events;
gboolean stop_after_next_frame;
GdkEventSequence *selected_sequence;
GtkInspectorEventRecording *last_event_recording;
};
typedef struct _GtkInspectorRecorderClass
@@ -735,7 +739,9 @@ show_event (GtkInspectorRecorder *recorder,
}
static void populate_event_properties (GListStore *store,
GdkEvent *event);
GdkEvent *event,
EventTrace *traces,
gsize n_traces);
static void
recording_selected (GtkSingleSelection *selection,
@@ -765,10 +771,13 @@ recording_selected (GtkSingleSelection *selection,
else if (GTK_INSPECTOR_IS_EVENT_RECORDING (recording))
{
GdkEvent *event;
EventTrace *traces;
gsize n_traces;
gtk_stack_set_visible_child_name (GTK_STACK (recorder->recording_data_stack), "event_data");
event = gtk_inspector_event_recording_get_event (GTK_INSPECTOR_EVENT_RECORDING (recording));
traces = gtk_inspector_event_recording_get_traces (GTK_INSPECTOR_EVENT_RECORDING (recording), &n_traces);
for (guint pos = gtk_single_selection_get_selected (selection) - 1; pos > 0; pos--)
{
@@ -785,7 +794,7 @@ recording_selected (GtkSingleSelection *selection,
}
}
populate_event_properties (recorder->event_properties, event);
populate_event_properties (recorder->event_properties, event, traces, n_traces);
if (recorder->highlight_sequences)
selected_sequence = gdk_event_get_event_sequence (event);
@@ -1738,7 +1747,9 @@ scroll_unit_name (GdkScrollUnit unit)
static void
populate_event_properties (GListStore *store,
GdkEvent *event)
GdkEvent *event,
EventTrace *traces,
gsize n_traces)
{
GdkEventType type;
GdkDevice *device;
@@ -1909,6 +1920,29 @@ populate_event_properties (GListStore *store,
g_free (history);
}
}
if (n_traces > 0)
{
GString *s = g_string_new ("");
const char *phase_name[] = { "", "", "", "" };
add_text_row (store, "Target", "%s", g_type_name (traces[0].target_type));
for (gsize i = 0; i < n_traces; i++)
{
EventTrace *t = &traces[i];
g_string_append_printf (s, "%s %s %s %s\n",
phase_name[t->phase],
g_type_name (t->widget_type),
g_type_name (t->controller_type),
t->handled ? "" : "");
g_string_append_c (s, '\n');
}
add_text_row (store, "Trace", "%s", s->str);
g_string_free (s, TRUE);
}
}
static GskRenderNode *
@@ -2033,22 +2067,13 @@ render_node_clip (GtkButton *button,
{
GskRenderNode *node;
GdkClipboard *clipboard;
GBytes *bytes;
GdkContentProvider *content;
node = get_selected_node (recorder);
if (node == NULL)
return;
bytes = gsk_render_node_serialize (node);
content = gdk_content_provider_new_for_bytes ("text/plain;charset=utf-8", bytes);
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (recorder));
gdk_clipboard_set_content (clipboard, content);
g_object_unref (content);
g_bytes_unref (bytes);
gdk_clipboard_set (clipboard, GSK_TYPE_RENDER_NODE, node);
}
static void
@@ -2450,6 +2475,7 @@ gtk_inspector_recorder_set_recording (GtkInspectorRecorder *recorder,
{
recorder->recording = gtk_inspector_start_recording_new ();
recorder->start_time = 0;
recorder->record_events = TRUE;
gtk_inspector_recorder_add_recording (recorder, recorder->recording);
}
else
@@ -2460,12 +2486,31 @@ gtk_inspector_recorder_set_recording (GtkInspectorRecorder *recorder,
g_object_notify_by_pspec (G_OBJECT (recorder), props[PROP_RECORDING]);
}
void
gtk_inspector_recorder_record_single_frame (GtkInspectorRecorder *recorder)
{
if (gtk_inspector_recorder_is_recording (recorder))
return;
recorder->recording = gtk_inspector_start_recording_new ();
recorder->start_time = 0;
recorder->record_events = FALSE;
recorder->stop_after_next_frame = TRUE;
gtk_inspector_recorder_add_recording (recorder, recorder->recording);
}
gboolean
gtk_inspector_recorder_is_recording (GtkInspectorRecorder *recorder)
{
return recorder->recording != NULL;
}
static gboolean
gtk_inspector_recorder_is_recording_events (GtkInspectorRecorder *recorder)
{
return recorder->recording != NULL && recorder->record_events;
}
void
gtk_inspector_recorder_record_render (GtkInspectorRecorder *recorder,
GtkWidget *widget,
@@ -2503,6 +2548,18 @@ gtk_inspector_recorder_record_render (GtkInspectorRecorder *recorder,
node);
gtk_inspector_recorder_add_recording (recorder, recording);
g_object_unref (recording);
if (recorder->stop_after_next_frame)
{
GtkSingleSelection *selection;
recorder->stop_after_next_frame = FALSE;
gtk_inspector_recorder_set_recording (recorder, FALSE);
selection = GTK_SINGLE_SELECTION (gtk_list_view_get_model (GTK_LIST_VIEW (recorder->recordings_list)));
gtk_single_selection_set_selected (selection, g_list_model_get_n_items (G_LIST_MODEL (selection)) - 1);
render_node_clip (NULL, recorder);
}
}
void
@@ -2514,7 +2571,7 @@ gtk_inspector_recorder_record_event (GtkInspectorRecorder *recorder,
GdkFrameClock *frame_clock;
gint64 frame_time;
if (!gtk_inspector_recorder_is_recording (recorder))
if (!gtk_inspector_recorder_is_recording_events (recorder))
return;
frame_clock = gtk_widget_get_frame_clock (widget);
@@ -2532,9 +2589,32 @@ gtk_inspector_recorder_record_event (GtkInspectorRecorder *recorder,
recording = gtk_inspector_event_recording_new (frame_time, event);
gtk_inspector_recorder_add_recording (recorder, recording);
recorder->last_event_recording = (GtkInspectorEventRecording *) recording;
g_object_unref (recording);
}
void
gtk_inspector_recorder_trace_event (GtkInspectorRecorder *recorder,
GdkEvent *event,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled)
{
GtkInspectorEventRecording *recording = recorder->last_event_recording;
if (!gtk_inspector_recorder_is_recording_events (recorder))
return;
if (recording == NULL || recording->event != event)
return;
gtk_inspector_event_recording_add_trace (recording, phase, widget, controller, target, handled);
}
void
gtk_inspector_recorder_set_debug_nodes (GtkInspectorRecorder *recorder,
gboolean debug_nodes)

View File

@@ -32,6 +32,7 @@ GType gtk_inspector_recorder_get_type (void);
void gtk_inspector_recorder_set_recording (GtkInspectorRecorder *recorder,
gboolean record);
gboolean gtk_inspector_recorder_is_recording (GtkInspectorRecorder *recorder);
void gtk_inspector_recorder_record_single_frame (GtkInspectorRecorder *recorder);
void gtk_inspector_recorder_set_debug_nodes (GtkInspectorRecorder *recorder,
gboolean debug_nodes);
@@ -52,6 +53,13 @@ void gtk_inspector_recorder_record_render (GtkInspectorRec
void gtk_inspector_recorder_record_event (GtkInspectorRecorder *recorder,
GtkWidget *widget,
GdkEvent *event);
void gtk_inspector_recorder_trace_event (GtkInspectorRecorder *recorder,
GdkEvent *event,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled);
G_END_DECLS

View File

@@ -893,6 +893,24 @@ gtk_inspector_handle_event (GdkEvent *event)
if (iw == NULL)
return FALSE;
if (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS))
{
GtkInspectorRecorder *recorder = GTK_INSPECTOR_RECORDER (iw->widget_recorder);
if (gdk_key_event_matches (event, GDK_KEY_r, GDK_SUPER_MASK) == GDK_KEY_MATCH_EXACT)
{
gboolean recording = gtk_inspector_recorder_is_recording (recorder);
gtk_inspector_recorder_set_recording (recorder, !recording);
return TRUE;
}
else if (gdk_key_event_matches (event, GDK_KEY_c, GDK_SUPER_MASK) == GDK_KEY_MATCH_EXACT)
{
gtk_inspector_recorder_record_single_frame (recorder);
return TRUE;
}
}
gtk_inspector_recorder_record_event (GTK_INSPECTOR_RECORDER (iw->widget_recorder),
gtk_get_event_widget (event),
event);
@@ -902,6 +920,27 @@ gtk_inspector_handle_event (GdkEvent *event)
return handled;
}
void
gtk_inspector_trace_event (GdkEvent *event,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled)
{
GtkInspectorWindow *iw;
if (!any_inspector_window_constructed)
return;
iw = gtk_inspector_window_get_for_display (gdk_event_get_display (event));
if (iw == NULL)
return;
gtk_inspector_recorder_trace_event (GTK_INSPECTOR_RECORDER (iw->widget_recorder),
event, phase, widget, controller, target, handled);
}
GdkDisplay *
gtk_inspector_window_get_inspected_display (GtkInspectorWindow *iw)
{

View File

@@ -149,14 +149,21 @@ void gtk_inspector_window_replace_object (GtkInspectorWindow
ChildKind kind,
guint position);
gboolean gtk_inspector_is_recording (GtkWidget *widget);
GskRenderNode * gtk_inspector_prepare_render (GtkWidget *widget,
GskRenderer *renderer,
GdkSurface *surface,
const cairo_region_t *region,
GskRenderNode *root,
GskRenderNode *widget_node);
gboolean gtk_inspector_handle_event (GdkEvent *event);
gboolean gtk_inspector_is_recording (GtkWidget *widget);
GskRenderNode * gtk_inspector_prepare_render (GtkWidget *widget,
GskRenderer *renderer,
GdkSurface *surface,
const cairo_region_t *region,
GskRenderNode *root,
GskRenderNode *widget_node);
gboolean gtk_inspector_handle_event (GdkEvent *event);
void gtk_inspector_trace_event (GdkEvent *event,
GtkPropagationPhase phase,
GtkWidget *widget,
GtkEventController *controller,
GtkWidget *target,
gboolean handled);
G_END_DECLS