gem-graph-client/libide/sourceview/ide-source-view-capture.c

273 lines
7.3 KiB
C

/* ide-source-view-capture.c
*
* Copyright 2015-2019 Christian Hergert <christian@hergert.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define G_LOG_DOMAIN "ide-source-view-capture"
#include <glib/gi18n.h>
#include "ide-source-view-capture.h"
#include "ide-source-view-private.h"
typedef struct
{
guint type : 1;
guint count : 31;
gunichar modifier;
GdkEvent *event;
} CaptureFrame;
enum {
FRAME_EVENT,
FRAME_MODIFIER,
};
struct _IdeSourceViewCapture
{
GObject parent_instance;
struct {
gchar *mode_name;
IdeSourceViewModeType mode_type;
guint count;
gunichar modifier;
} starting_state;
IdeSourceView *view;
GArray *frames;
};
G_DEFINE_FINAL_TYPE (IdeSourceViewCapture, ide_source_view_capture, G_TYPE_OBJECT)
enum {
PROP_0,
PROP_VIEW,
LAST_PROP
};
static GParamSpec *properties [LAST_PROP];
IdeSourceViewCapture *
ide_source_view_capture_new (IdeSourceView *view,
const gchar *mode_name,
IdeSourceViewModeType mode_type,
guint count,
gunichar modifier)
{
IdeSourceViewCapture *self;
self = g_object_new (IDE_TYPE_SOURCE_VIEW_CAPTURE,
"view", view,
NULL);
self->starting_state.mode_name = g_strdup (mode_name);
self->starting_state.mode_type = mode_type;
self->starting_state.count = count;
self->starting_state.modifier = modifier;
return self;
}
IdeSourceView *
ide_source_view_capture_get_view (IdeSourceViewCapture *self)
{
g_return_val_if_fail (IDE_IS_SOURCE_VIEW_CAPTURE (self), NULL);
return self->view;
}
static void
ide_source_view_capture_set_view (IdeSourceViewCapture *self,
IdeSourceView *view)
{
g_return_if_fail (IDE_IS_SOURCE_VIEW_CAPTURE (self));
g_set_object (&self->view, view);
}
void
ide_source_view_capture_replay (IdeSourceViewCapture *self)
{
gsize i;
g_return_if_fail (IDE_IS_SOURCE_VIEW_CAPTURE (self));
g_signal_emit_by_name (self->view,
"set-mode",
self->starting_state.mode_name,
self->starting_state.mode_type);
_ide_source_view_set_count (self->view, self->starting_state.count);
_ide_source_view_set_modifier (self->view, self->starting_state.modifier);
for (i = 0; i < self->frames->len; i++)
{
CaptureFrame *frame;
frame = &g_array_index (self->frames, CaptureFrame, i);
switch (frame->type)
{
case FRAME_EVENT:
_ide_source_view_set_count (self->view, frame->count);
_ide_source_view_set_modifier (self->view, frame->modifier);
gtk_widget_event (GTK_WIDGET (self->view), frame->event);
break;
case FRAME_MODIFIER:
_ide_source_view_set_modifier (self->view, frame->modifier);
break;
default:
g_assert_not_reached ();
break;
}
}
}
void
ide_source_view_capture_record_modifier (IdeSourceViewCapture *self,
gunichar modifier)
{
CaptureFrame frame = { 0 };
CaptureFrame* last;
g_assert (IDE_IS_SOURCE_VIEW_CAPTURE (self));
if (self->frames->len > 0)
{
last = &g_array_index (self->frames, CaptureFrame, self->frames->len - 1);
if (last->modifier == 0)
{
last->modifier = modifier;
return;
}
}
frame.type = FRAME_MODIFIER;
frame.count = 0;
frame.modifier = modifier;
frame.event = NULL;
g_array_append_val (self->frames, frame);
}
void
ide_source_view_capture_record_event (IdeSourceViewCapture *self,
const GdkEvent *event,
guint count,
gunichar modifier)
{
CaptureFrame frame = { 0 };
g_assert (IDE_IS_SOURCE_VIEW_CAPTURE (self));
g_assert (event);
frame.type = FRAME_EVENT;
frame.count = (count & 0x7FFFFFFF);
frame.modifier = modifier;
frame.event = gdk_event_copy ((GdkEvent*)event);
g_array_append_val (self->frames, frame);
}
static void
clear_frame (CaptureFrame *frame)
{
g_clear_pointer (&frame->event, gdk_event_free);
}
static void
ide_source_view_capture_finalize (GObject *object)
{
IdeSourceViewCapture *self = (IdeSourceViewCapture *)object;
g_clear_object (&self->view);
g_clear_pointer (&self->frames, g_array_unref);
g_clear_pointer (&self->starting_state.mode_name, g_free);
G_OBJECT_CLASS (ide_source_view_capture_parent_class)->finalize (object);
}
static void
ide_source_view_capture_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
IdeSourceViewCapture *self = IDE_SOURCE_VIEW_CAPTURE (object);
switch (prop_id)
{
case PROP_VIEW:
g_value_set_object (value, ide_source_view_capture_get_view (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_source_view_capture_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
IdeSourceViewCapture *self = IDE_SOURCE_VIEW_CAPTURE (object);
switch (prop_id)
{
case PROP_VIEW:
ide_source_view_capture_set_view (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ide_source_view_capture_class_init (IdeSourceViewCaptureClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = ide_source_view_capture_finalize;
object_class->get_property = ide_source_view_capture_get_property;
object_class->set_property = ide_source_view_capture_set_property;
properties [PROP_VIEW] =
g_param_spec_object ("view",
"View",
"The source view.",
IDE_TYPE_SOURCE_VIEW,
(G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
}
static void
ide_source_view_capture_init (IdeSourceViewCapture *self)
{
self->frames = g_array_new (FALSE, FALSE, sizeof(CaptureFrame));
g_array_set_clear_func (self->frames, (GDestroyNotify)clear_frame);
}