Merge branch 'event-recorder' into 'main'

inspector: Add axes to event details in recorder

See merge request GNOME/gtk!4258
This commit is contained in:
Matthias Clasen 2021-12-16 04:34:01 +00:00
commit 0682a5e45e
14 changed files with 489 additions and 61 deletions

View File

@ -942,6 +942,9 @@ gdk_event_get_pointer_emulated (GdkEvent *event)
* Extract the axis value for a particular axis use from
* an event structure.
*
* To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
* on the device tool returned by [method@Gdk.Event.get_device_tool].
*
* Returns: %TRUE if the specified axis was found, otherwise %FALSE
*/
gboolean
@ -1168,6 +1171,9 @@ G_DEFINE_BOXED_TYPE (GdkEventSequence, gdk_event_sequence,
*
* Extracts all axis values from an event.
*
* To find out which axes are used, use [method@Gdk.DeviceTool.get_axes]
* on the device tool returned by [method@Gdk.Event.get_device_tool].
*
* Returns: %TRUE on success, otherwise %FALSE
*/
gboolean
@ -2470,6 +2476,14 @@ gdk_touchpad_event_get_state (GdkEvent *event)
return self->state;
}
static GdkEventSequence *
gdk_touchpad_event_get_sequence (GdkEvent *event)
{
GdkTouchpadEvent *self = (GdkTouchpadEvent *) event;
return self->sequence;
}
static gboolean
gdk_touchpad_event_get_position (GdkEvent *event,
double *x,
@ -2489,7 +2503,7 @@ static const GdkEventTypeInfo gdk_touchpad_event_info = {
NULL,
gdk_touchpad_event_get_state,
gdk_touchpad_event_get_position,
NULL,
gdk_touchpad_event_get_sequence,
NULL,
NULL,
};
@ -2500,19 +2514,28 @@ GDK_DEFINE_EVENT_TYPE (GdkTouchpadEvent, gdk_touchpad_event,
GDK_EVENT_TYPE_SLOT (GDK_TOUCHPAD_PINCH))
GdkEvent *
gdk_touchpad_event_new_swipe (GdkSurface *surface,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkTouchpadGesturePhase phase,
double x,
double y,
int n_fingers,
double dx,
double dy)
gdk_touchpad_event_new_swipe (GdkSurface *surface,
GdkEventSequence *sequence,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkTouchpadGesturePhase phase,
double x,
double y,
int n_fingers,
double dx,
double dy)
{
GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_SWIPE, surface, device, time);
GdkTouchpadEvent *self;
g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
self = gdk_event_alloc (GDK_TOUCHPAD_SWIPE, surface, device, time);
self->sequence = sequence;
self->state = state;
self->phase = phase;
self->x = x;
@ -2525,21 +2548,30 @@ gdk_touchpad_event_new_swipe (GdkSurface *surface,
}
GdkEvent *
gdk_touchpad_event_new_pinch (GdkSurface *surface,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkTouchpadGesturePhase phase,
double x,
double y,
int n_fingers,
double dx,
double dy,
double scale,
double angle_delta)
gdk_touchpad_event_new_pinch (GdkSurface *surface,
GdkEventSequence *sequence,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkTouchpadGesturePhase phase,
double x,
double y,
int n_fingers,
double dx,
double dy,
double scale,
double angle_delta)
{
GdkTouchpadEvent *self = gdk_event_alloc (GDK_TOUCHPAD_PINCH, surface, device, time);
GdkTouchpadEvent *self;
g_return_val_if_fail (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_END ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_UPDATE ||
phase == GDK_TOUCHPAD_GESTURE_PHASE_CANCEL, NULL);
self = gdk_event_alloc (GDK_TOUCHPAD_PINCH, surface, device, time);
self->sequence = sequence;
self->state = state;
self->phase = phase;
self->x = x;

View File

@ -402,6 +402,7 @@ struct _GdkTouchpadEvent
{
GdkEvent parent_instance;
GdkEventSequence *sequence;
GdkModifierType state;
gint8 phase;
gint8 n_fingers;
@ -506,18 +507,20 @@ GdkEvent * gdk_touch_event_new (GdkEventType type,
double *axes,
gboolean emulating);
GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface *surface,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkEvent * gdk_touchpad_event_new_swipe (GdkSurface *surface,
GdkEventSequence *sequence,
GdkDevice *device,
guint32 time,
GdkModifierType state,
GdkTouchpadGesturePhase phase,
double x,
double y,
int n_fingers,
double dx,
double dy);
double x,
double y,
int n_fingers,
double dx,
double dy);
GdkEvent * gdk_touchpad_event_new_pinch (GdkSurface *surface,
GdkEventSequence *sequence,
GdkDevice *device,
guint32 time,
GdkModifierType state,

View File

@ -537,6 +537,7 @@ fill_pinch_event (GdkMacosDisplay *display,
seat = gdk_display_get_default_seat (GDK_DISPLAY (display));
return gdk_touchpad_event_new_pinch (GDK_SURFACE (surface),
NULL, /* FIXME make up sequences */
gdk_seat_get_pointer (seat),
get_time_from_ns_event (nsevent),
get_keyboard_modifiers_from_ns_event (nsevent),

View File

@ -137,6 +137,7 @@ struct _GdkWaylandPointerData {
guint cursor_timeout_id;
guint cursor_image_index;
guint cursor_image_delay;
guint touchpad_event_sequence;
guint current_output_scale;
GSList *pointer_surface_outputs;
@ -1127,7 +1128,7 @@ data_offer_source_actions (void *data,
seat->pending_source_actions = gdk_wayland_actions_to_gdk_actions (source_actions);
return;
}
if (seat->drop == NULL)
return;
@ -1152,7 +1153,7 @@ data_offer_action (void *data,
seat->pending_action = gdk_wayland_actions_to_gdk_actions (action);
return;
}
if (seat->drop == NULL)
return;
@ -2164,7 +2165,7 @@ deliver_key_event (GdkWaylandSeat *seat,
key,
device_get_modifiers (seat->logical_pointer),
_gdk_wayland_keymap_key_is_modifier (keymap, key),
&translated,
&translated,
&no_lock);
_gdk_wayland_display_deliver_event (seat->display, event);
@ -2667,7 +2668,11 @@ emit_gesture_swipe_event (GdkWaylandSeat *seat,
seat->pointer_info.time = _time;
if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
seat->pointer_info.touchpad_event_sequence++;
event = gdk_touchpad_event_new_swipe (seat->pointer_info.focus,
GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
seat->logical_pointer,
_time,
device_get_modifiers (seat->logical_pointer),
@ -2763,7 +2768,11 @@ emit_gesture_pinch_event (GdkWaylandSeat *seat,
seat->pointer_info.time = _time;
if (phase == GDK_TOUCHPAD_GESTURE_PHASE_BEGIN)
seat->pointer_info.touchpad_event_sequence++;
event = gdk_touchpad_event_new_pinch (seat->pointer_info.focus,
GDK_SLOT_TO_EVENT_SEQUENCE (seat->pointer_info.touchpad_event_sequence),
seat->logical_pointer,
_time,
device_get_modifiers (seat->logical_pointer),
@ -4088,7 +4097,7 @@ tablet_pad_strip_handle_frame (void *data,
event = gdk_pad_event_new_strip (seat->keyboard_focus,
pad->device,
time,
g_list_index (pad->mode_groups, group),
g_list_index (pad->mode_groups, group),
g_list_index (pad->strips, wp_tablet_pad_strip),
group->current_mode,
group->axis_tmp_info.value);

View File

@ -1665,7 +1665,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
direction,
FALSE);
}
else
{
@ -1799,7 +1799,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
_gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group),
x, y,
axes);
}
break;
@ -1838,7 +1838,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
x = (double) xev->event_x / scale;
y = (double) xev->event_y / scale;
event = gdk_touch_event_new (ev->evtype == XI_TouchBegin
? GDK_TOUCH_BEGIN
: GDK_TOUCH_END,
@ -1946,6 +1946,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
y = (double) xev->event_y / scale;
event = gdk_touchpad_event_new_pinch (surface,
NULL, /* FIXME make up sequences */
device,
xev->time,
state,
@ -2006,6 +2007,7 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
y = (double) xev->event_y / scale;
event = gdk_touchpad_event_new_swipe (surface,
NULL, /* FIXME make up sequences */
device,
xev->time,
state,

View File

@ -951,6 +951,7 @@ rewrite_event_for_surface (GdkEvent *event,
case GDK_TOUCHPAD_SWIPE:
gdk_touchpad_event_get_deltas (event, &dx, &dy);
return gdk_touchpad_event_new_swipe (new_surface,
gdk_event_get_event_sequence (event),
gdk_event_get_device (event),
gdk_event_get_time (event),
gdk_event_get_modifier_state (event),
@ -961,6 +962,7 @@ rewrite_event_for_surface (GdkEvent *event,
case GDK_TOUCHPAD_PINCH:
gdk_touchpad_event_get_deltas (event, &dx, &dy);
return gdk_touchpad_event_new_pinch (new_surface,
gdk_event_get_event_sequence (event),
gdk_event_get_device (event),
gdk_event_get_time (event),
gdk_event_get_modifier_state (event),

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="16px" viewBox="0 0 16 16" width="16px"><filter id="a" height="100%" width="100%" x="0%" y="0%"><feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="b"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/></g></mask><clipPath id="c"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="d"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="e"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="f"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="g"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="h"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="i"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="j"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="k"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="l"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="m"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="n"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="o"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="p"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/></g></mask><clipPath id="q"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="r"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/></g></mask><clipPath id="s"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/></g><g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 16 748 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 17 747 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 18 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 16 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 17 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 19 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 136 776 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/></g><g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -16 -816)"><path d="m 219 758 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/></g><g fill="#2e3436"><path d="m 11.507812 3.078125 l -8.429687 8.429687 c 0.765625 0.039063 1.375 0.648438 1.414063 1.414063 l 8.429687 -8.429687 c -0.765625 -0.039063 -1.375 -0.648438 -1.414063 -1.414063 z m 0 0"/><path d="m 3 11 c -1.097656 0 -2 0.902344 -2 2 s 0.902344 2 2 2 s 2 -0.902344 2 -2 s -0.902344 -2 -2 -2 z m 0 1 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 0 0"/><path d="m 13 1 c -1.097656 0 -2 0.902344 -2 2 s 0.902344 2 2 2 s 2 -0.902344 2 -2 s -0.902344 -2 -2 -2 z m 0 1 c 0.558594 0 1 0.441406 1 1 s -0.441406 1 -1 1 s -1 -0.441406 -1 -1 s 0.441406 -1 1 -1 z m 0 0"/></g></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -55,3 +55,7 @@ picture.light {
min-width: 10px;
min-height: 10px;
}
row:not(:selected) > .highlight {
background-color: rgba(135, 206, 250, 0.4);
}

View File

@ -31,6 +31,7 @@ inspector_sources = files(
'prop-holder.c',
'prop-list.c',
'recorder.c',
'recorderrow.c',
'recording.c',
'renderrecording.c',
'resource-holder.c',

View File

@ -55,6 +55,7 @@
#include "renderrecording.h"
#include "startrecording.h"
#include "eventrecording.h"
#include "recorderrow.h"
struct _GtkInspectorRecorder
{
@ -82,6 +83,9 @@ struct _GtkInspectorRecorder
gint64 start_time;
gboolean debug_nodes;
gboolean highlight_sequences;
GdkEventSequence *selected_sequence;
};
typedef struct _GtkInspectorRecorderClass
@ -95,6 +99,8 @@ enum
PROP_0,
PROP_RECORDING,
PROP_DEBUG_NODES,
PROP_HIGHLIGHT_SEQUENCES,
PROP_SELECTED_SEQUENCE,
LAST_PROP
};
@ -506,6 +512,7 @@ recording_selected (GtkSingleSelection *selection,
GtkInspectorRecorder *recorder)
{
GtkInspectorRecording *recording;
GdkEventSequence *selected_sequence = NULL;
if (recorder->recordings == NULL)
{
@ -548,6 +555,9 @@ recording_selected (GtkSingleSelection *selection,
}
populate_event_properties (GTK_LIST_STORE (recorder->event_properties), event);
if (recorder->highlight_sequences)
selected_sequence = gdk_event_get_event_sequence (event);
}
else
{
@ -556,6 +566,8 @@ recording_selected (GtkSingleSelection *selection,
gtk_picture_set_paintable (GTK_PICTURE (recorder->render_node_view), NULL);
g_list_store_remove_all (recorder->render_node_root_model);
}
gtk_inspector_recorder_set_selected_sequence (recorder, selected_sequence);
}
static GdkTexture *
@ -1360,13 +1372,66 @@ key_event_string (GdkEvent *event)
return g_strdup (gdk_keyval_name (keyval));
}
static const char *
device_tool_name (GdkDeviceTool *tool)
{
const char *name[] = {
"Unknown",
"Pen",
"Eraser",
"Brush",
"Pencil",
"Airbrush",
"Mouse",
"Lens"
};
return name[gdk_device_tool_get_tool_type (tool)];
}
static const char *
axis_name (GdkAxisUse axis)
{
const char *name[] = {
"",
"X",
"Y",
"Delta X",
"Delta Y",
"Pressure",
"X Tilt",
"Y Tilt",
"Wheel",
"Distance",
"Rotation",
"Slider"
};
return name[axis];
}
static const char *
gesture_phase_name (GdkTouchpadGesturePhase phase)
{
const char *name[] = {
"Begin",
"Update",
"End",
"Cancel"
};
return name[phase];
}
static void
populate_event_properties (GtkListStore *store,
GdkEvent *event)
{
GdkEventType type;
GdkDevice *device;
GdkDeviceTool *tool;
double x, y;
double dx, dy;
char *tmp;
GdkModifierType state;
@ -1375,12 +1440,22 @@ populate_event_properties (GtkListStore *store,
type = gdk_event_get_event_type (event);
add_text_row (store, "Type", event_type_name (type));
if (gdk_event_get_event_sequence (event) != NULL)
{
tmp = g_strdup_printf ("%p", gdk_event_get_event_sequence (event));
add_text_row (store, "Sequence", tmp);
g_free (tmp);
}
add_int_row (store, "Timestamp", gdk_event_get_time (event));
device = gdk_event_get_device (event);
if (device)
add_text_row (store, "Device", gdk_device_get_name (device));
tool = gdk_event_get_device_tool (event);
if (tool)
add_text_row (store, "Device Tool", device_tool_name (tool));
if (gdk_event_get_position (event, &x, &y))
{
tmp = g_strdup_printf ("%.2f %.2f", x, y);
@ -1388,6 +1463,26 @@ populate_event_properties (GtkListStore *store,
g_free (tmp);
}
if (tool)
{
GdkAxisFlags axes = gdk_device_tool_get_axes (tool);
/* We report position and scroll delta separately, so skip them here */
axes &= ~(GDK_AXIS_FLAG_X|GDK_AXIS_FLAG_Y|GDK_AXIS_FLAG_DELTA_X|GDK_AXIS_FLAG_DELTA_Y);
for (int i = 1; i < GDK_AXIS_LAST; i++)
{
if (axes & (1 << i))
{
double val;
gdk_event_get_axis (event, i, &val);
tmp = g_strdup_printf ("%.2f", val);
add_text_row (store, axis_name (i), tmp);
g_free (tmp);
}
}
}
state = gdk_event_get_modifier_state (event);
if (state != 0)
{
@ -1445,6 +1540,25 @@ populate_event_properties (GtkListStore *store,
add_boolean_row (store, "Implicit", gdk_grab_broken_event_get_implicit (event));
break;
case GDK_TOUCHPAD_SWIPE:
case GDK_TOUCHPAD_PINCH:
add_text_row (store, "Phase", gesture_phase_name (gdk_touchpad_event_get_gesture_phase (event)));
add_int_row (store, "Fingers", gdk_touchpad_event_get_n_fingers (event));
gdk_touchpad_event_get_deltas (event, &dx, &dy);
tmp = g_strdup_printf ("%.2f %.f2", dx, dy);
add_text_row (store, "Delta", tmp);
g_free (tmp);
if (type == GDK_TOUCHPAD_PINCH)
{
tmp = g_strdup_printf ("%.2f", gdk_touchpad_event_get_pinch_angle_delta (event));
add_text_row (store, "Angle Delta", tmp);
g_free (tmp);
tmp = g_strdup_printf ("%.2f", gdk_touchpad_event_get_pinch_scale (event));
add_text_row (store, "Scale", tmp);
g_free (tmp);
}
break;
default:
/* FIXME */
;
@ -1458,18 +1572,26 @@ populate_event_properties (GtkListStore *store,
history = gdk_event_get_history (event, &n_coords);
if (history)
{
GString *s;
s = g_string_new ("");
GString *s = g_string_new ("");
for (int i = 0; i < n_coords; i++)
{
if (i > 0)
g_string_append (s, "\n");
if ((history[i].flags & (GDK_AXIS_FLAG_X|GDK_AXIS_FLAG_Y)) == (GDK_AXIS_FLAG_X|GDK_AXIS_FLAG_Y))
g_string_append_printf (s, "%d: %.2f %.2f", history[i].time, history[i].axes[GDK_AXIS_X], history[i].axes[GDK_AXIS_Y]);
if ((history[i].flags & (GDK_AXIS_FLAG_DELTA_X|GDK_AXIS_FLAG_DELTA_Y)) == (GDK_AXIS_FLAG_DELTA_X|GDK_AXIS_FLAG_DELTA_Y))
g_string_append_printf (s, "%d: %.2f %.2f", history[i].time, history[i].axes[GDK_AXIS_DELTA_X], history[i].axes[GDK_AXIS_DELTA_Y]);
g_string_append_printf (s, "%d", history[i].time);
if (history[i].flags & (GDK_AXIS_FLAG_X|GDK_AXIS_FLAG_Y))
g_string_append_printf (s, " Position %.2f %.2f", history[i].axes[GDK_AXIS_X], history[i].axes[GDK_AXIS_Y]);
if (history[i].flags & (GDK_AXIS_FLAG_DELTA_X|GDK_AXIS_FLAG_DELTA_Y))
g_string_append_printf (s, " Delta %.2f %.2f", history[i].axes[GDK_AXIS_DELTA_X], history[i].axes[GDK_AXIS_DELTA_Y]);
for (int j = GDK_AXIS_PRESSURE; j < GDK_AXIS_LAST; j++)
{
if (history[i].flags & (1 << j))
g_string_append_printf (s, " %s %.2f", axis_name (j), history[i].axes[j]);
}
}
add_text_row (store, "History", s->str);
@ -1643,23 +1765,27 @@ setup_widget_for_recording (GtkListItemFactory *factory,
GtkListItem *item,
gpointer data)
{
GtkWidget *widget, *label;
GtkWidget *row, *box, *label;
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
row = g_object_new (GTK_TYPE_INSPECTOR_RECORDER_ROW, NULL);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("");
gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
gtk_widget_set_hexpand (label, TRUE);
gtk_box_append (GTK_BOX (widget), label);
gtk_box_append (GTK_BOX (box), label);
label = gtk_label_new ("");
gtk_box_append (GTK_BOX (widget), label);
gtk_box_append (GTK_BOX (box), label);
gtk_widget_set_margin_start (widget, 6);
gtk_widget_set_margin_end (widget, 6);
gtk_widget_set_margin_top (widget, 6);
gtk_widget_set_margin_bottom (widget, 6);
gtk_widget_set_margin_start (box, 6);
gtk_widget_set_margin_end (box, 6);
gtk_widget_set_margin_top (box, 6);
gtk_widget_set_margin_bottom (box, 6);
gtk_list_item_set_child (item, widget);
gtk_widget_set_parent (box, row);
gtk_list_item_set_child (item, row);
}
static char *
@ -1737,14 +1863,19 @@ bind_widget_for_recording (GtkListItemFactory *factory,
GtkListItem *item,
gpointer data)
{
GtkInspectorRecorder *recorder = GTK_INSPECTOR_RECORDER (data);
GtkInspectorRecording *recording = gtk_list_item_get_item (item);
GtkWidget *widget, *label, *label2;
GtkWidget *row, *box, *label, *label2;
char *text;
widget = gtk_list_item_get_child (item);
label = gtk_widget_get_first_child (widget);
row = gtk_list_item_get_child (item);
box = gtk_widget_get_first_child (row);
label = gtk_widget_get_first_child (box);
label2 = gtk_widget_get_next_sibling (label);
g_object_set (row, "sequence", NULL, NULL);
g_object_bind_property (recorder, "selected-sequence", row, "match-sequence", G_BINDING_SYNC_CREATE);
gtk_label_set_use_markup (GTK_LABEL (label), FALSE);
if (GTK_INSPECTOR_IS_RENDER_RECORDING (recording))
@ -1760,6 +1891,8 @@ bind_widget_for_recording (GtkListItemFactory *factory,
{
GdkEvent *event = gtk_inspector_event_recording_get_event (GTK_INSPECTOR_EVENT_RECORDING (recording));
g_object_set (row, "sequence", gdk_event_get_event_sequence (event), NULL);
text = get_event_summary (event);
gtk_label_set_label (GTK_LABEL (label), text);
g_free (text);
@ -1835,6 +1968,14 @@ gtk_inspector_recorder_get_property (GObject *object,
g_value_set_boolean (value, recorder->debug_nodes);
break;
case PROP_HIGHLIGHT_SEQUENCES:
g_value_set_boolean (value, recorder->highlight_sequences);
break;
case PROP_SELECTED_SEQUENCE:
g_value_set_pointer (value, recorder->selected_sequence);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@ -1859,6 +2000,14 @@ gtk_inspector_recorder_set_property (GObject *object,
gtk_inspector_recorder_set_debug_nodes (recorder, g_value_get_boolean (value));
break;
case PROP_HIGHLIGHT_SEQUENCES:
gtk_inspector_recorder_set_highlight_sequences (recorder, g_value_get_boolean (value));
break;
case PROP_SELECTED_SEQUENCE:
recorder->selected_sequence = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@ -1901,6 +2050,9 @@ gtk_inspector_recorder_class_init (GtkInspectorRecorderClass *klass)
FALSE,
G_PARAM_READWRITE);
props[PROP_HIGHLIGHT_SEQUENCES] = g_param_spec_boolean ("highlight-sequences", "", "", FALSE, G_PARAM_READWRITE);
props[PROP_SELECTED_SEQUENCE] = g_param_spec_pointer ("selected-sequence", "", "", G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, props);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/recorder.ui");
@ -2093,4 +2245,48 @@ gtk_inspector_recorder_set_debug_nodes (GtkInspectorRecorder *recorder,
g_object_notify_by_pspec (G_OBJECT (recorder), props[PROP_DEBUG_NODES]);
}
// vim: set et sw=2 ts=2:
void
gtk_inspector_recorder_set_highlight_sequences (GtkInspectorRecorder *recorder,
gboolean highlight_sequences)
{
GdkEventSequence *sequence = NULL;
if (recorder->highlight_sequences == highlight_sequences)
return;
recorder->highlight_sequences = highlight_sequences;
if (highlight_sequences)
{
GtkSingleSelection *selection;
GtkInspectorRecording *recording;
GdkEvent *event;
selection = GTK_SINGLE_SELECTION (gtk_list_view_get_model (GTK_LIST_VIEW (recorder->recordings_list)));
recording = gtk_single_selection_get_selected_item (selection);
if (GTK_INSPECTOR_IS_EVENT_RECORDING (recording))
{
event = gtk_inspector_event_recording_get_event (GTK_INSPECTOR_EVENT_RECORDING (recording));
sequence = gdk_event_get_event_sequence (event);
}
}
gtk_inspector_recorder_set_selected_sequence (recorder, sequence);
g_object_notify_by_pspec (G_OBJECT (recorder), props[PROP_HIGHLIGHT_SEQUENCES]);
}
void
gtk_inspector_recorder_set_selected_sequence (GtkInspectorRecorder *recorder,
GdkEventSequence *sequence)
{
if (recorder->selected_sequence == sequence)
return;
recorder->selected_sequence = sequence;
g_object_notify_by_pspec (G_OBJECT (recorder), props[PROP_SELECTED_SEQUENCE]);
}

View File

@ -37,6 +37,12 @@ gboolean gtk_inspector_recorder_is_recording (GtkInspectorRec
void gtk_inspector_recorder_set_debug_nodes (GtkInspectorRecorder *recorder,
gboolean debug_nodes);
void gtk_inspector_recorder_set_highlight_sequences (GtkInspectorRecorder *recorder,
gboolean highlight_sequences);
void gtk_inspector_recorder_set_selected_sequence (GtkInspectorRecorder *recorder,
GdkEventSequence *sequence);
void gtk_inspector_recorder_record_render (GtkInspectorRecorder *recorder,
GtkWidget *widget,
GskRenderer *renderer,

View File

@ -34,6 +34,14 @@
<property name="tooltip-text" translatable="yes">Add debug nodes</property>
<property name="active" bind-source="GtkInspectorRecorder" bind-property="debug-nodes" bind-flags="bidirectional|sync-create"/>
<property name="halign">start</property>
</object>
</child>
<child>
<object class="GtkToggleButton">
<property name="icon-name">function-linear-symbolic</property>
<property name="tooltip-text" translatable="yes">Highlight event sequences</property>
<property name="active" bind-source="GtkInspectorRecorder" bind-property="highlight-sequences" bind-flags="bidirectional|sync-create"/>
<property name="halign">start</property>
<property name="hexpand">1</property>
</object>
</child>

138
gtk/inspector/recorderrow.c Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include "recorderrow.h"
#include <gtk/gtkbinlayout.h>
/* This is a minimal widget whose purpose it is to compare the event sequence
* of its row in the recordings list with the event sequence of the selected
* row, and highlight itself if they match.
*/
struct _GtkInspectorRecorderRow
{
GtkWidget parent;
gpointer sequence;
gpointer match_sequence;
};
enum {
PROP_SEQUENCE = 1,
PROP_MATCH_SEQUENCE,
LAST_PROP
};
static GParamSpec *props[LAST_PROP] = { NULL, };
G_DEFINE_TYPE (GtkInspectorRecorderRow, gtk_inspector_recorder_row, GTK_TYPE_WIDGET)
static void
gtk_inspector_recorder_row_init (GtkInspectorRecorderRow *self)
{
}
static void
dispose (GObject *object)
{
GtkInspectorRecorderRow *self = GTK_INSPECTOR_RECORDER_ROW (object);
gtk_widget_unparent (gtk_widget_get_first_child (GTK_WIDGET (self)));
G_OBJECT_CLASS (gtk_inspector_recorder_row_parent_class)->dispose (object);
}
static void
update_style (GtkInspectorRecorderRow *self)
{
if (self->sequence == self->match_sequence && self->sequence != NULL)
gtk_widget_add_css_class (GTK_WIDGET (self), "highlight");
else
gtk_widget_remove_css_class (GTK_WIDGET (self), "highlight");
}
static void
gtk_inspector_recorder_row_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
GtkInspectorRecorderRow *self = GTK_INSPECTOR_RECORDER_ROW (object);
switch (param_id)
{
case PROP_SEQUENCE:
g_value_set_pointer (value, self->sequence);
break;
case PROP_MATCH_SEQUENCE:
g_value_set_pointer (value, self->match_sequence);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_inspector_recorder_row_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
GtkInspectorRecorderRow *self = GTK_INSPECTOR_RECORDER_ROW (object);
switch (param_id)
{
case PROP_SEQUENCE:
self->sequence = g_value_get_pointer (value);
update_style (self);
break;
case PROP_MATCH_SEQUENCE:
self->match_sequence = g_value_get_pointer (value);
update_style (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
gtk_inspector_recorder_row_class_init (GtkInspectorRecorderRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = dispose;
object_class->set_property = gtk_inspector_recorder_row_set_property;
object_class->get_property = gtk_inspector_recorder_row_get_property;
props[PROP_SEQUENCE] = g_param_spec_pointer ("sequence", "", "", G_PARAM_READWRITE);
props[PROP_MATCH_SEQUENCE] = g_param_spec_pointer ("match-sequence", "", "", G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, props);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtkwidget.h>
#define GTK_TYPE_INSPECTOR_RECORDER_ROW (gtk_inspector_recorder_row_get_type ())
G_DECLARE_FINAL_TYPE (GtkInspectorRecorderRow, gtk_inspector_recorder_row, GTK, INSPECTOR_RECORDER_ROW, GtkWidget)