talkatu/talkatu

Fix the input in the demo.
gtk4
2022-02-03, Gary Kramlich
1819a3f27516
Fix the input in the demo.

We had some over zealous can-focus's set to 0 which was the main issue. The
other stuff was just stuff to clean up I found along the way.

Testing Done:
Ran the demo verified I can input text. Sending is still broken but that's another matter entirely...

Reviewed at https://reviews.imfreedom.org/r/1283/
/*
* Talkatu - GTK widgets for chat applications
* Copyright (C) 2017-2022 Gary Kramlich <grim@reaperworld.com>
*
* This library 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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library; if not, see <https://www.gnu.org/licenses/>.
*/
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include "talkatu/talkatuinput.h"
#include "talkatu/talkatuactiongroup.h"
#include "talkatu/talkatuattachmentdialog.h"
#include "talkatu/talkatuenums.h"
#include "talkatu/talkatumarkup.h"
#include "talkatu/talkatumessage.h"
#include "talkatu/talkatusimpleattachment.h"
/**
* TalkatuInput:
*
* #TalkatuInput is the main input widget for Talkatu. It supports WYSIWYG
* input for both HTML and Markdown as well as plain text.
*
* It implements #TalkatuMessage which means it can be written directly to
* #TalkatuHistory with talkatu_history_write_message(). That also means that
* it can handle attachments. Currently this is only supported programmatically.
*
* It provides keybinds for pasting images as well as emitting a signal when the
* user has pressed a developer defined keybinding to "send" the message.
*/
/**
* TalkatuInputClass:
* @send_message: The class handler for the #TalkatuInput::send_message signal.
*
* The backing class to #TalkatuInput instances.
*/
/**
* TalkatuInputSendBinding:
* @TALKATU_INPUT_SEND_BINDING_RETURN: Represents return.
* @TALKATU_INPUT_SEND_BINDING_KP_ENTER: Represents enter.
* @TALKATU_INPUT_SEND_BINDING_SHIFT_RETURN: Represents shift-return.
* @TALKATU_INPUT_SEND_BINDING_CONTROL_RETURN: Represents control-return.
*
* Flags for assigning and determining which key bindings should be used to
* send a message.
*/
typedef struct {
GHashTable *attachments;
guint64 attachment_id;
TalkatuInputSendBinding send_binding;
/* TalkatuMessage properties: content type and contents are derived from
* the widget itself.
*/
gchar *id;
GDateTime *timestamp;
TalkatuContentType content_type;
gchar *author;
GdkRGBA *author_name_color;
gboolean edited;
} TalkatuInputPrivate;
typedef struct {
TalkatuAttachmentForeachFunc func;
gpointer data;
} TalkatuInputForeachAttachmentData;
enum {
PROP_0 = 0,
PROP_SEND_BINDING,
N_PROPERTIES,
/* overrides */
PROP_ID = N_PROPERTIES,
PROP_TIMESTAMP,
PROP_CONTENT_TYPE,
PROP_AUTHOR,
PROP_AUTHOR_NAME_COLOR,
PROP_CONTENTS,
PROP_EDITED,
};
static GParamSpec *properties[N_PROPERTIES];
enum {
SIG_SHOULD_SEND_MESSAGE,
SIG_SEND_MESSAGE,
LAST_SIGNAL,
};
static guint signals[LAST_SIGNAL] = {0, };
static void talkatu_input_message_init(TalkatuMessageInterface *iface);
G_DEFINE_TYPE_EXTENDED(
TalkatuInput, talkatu_input, TALKATU_TYPE_VIEW,
0,
G_ADD_PRIVATE(TalkatuInput)
G_IMPLEMENT_INTERFACE(TALKATU_TYPE_MESSAGE, talkatu_input_message_init)
);
/******************************************************************************
* TalkatuMessage Interface
*****************************************************************************/
static const gchar *
talkatu_input_get_id(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
return priv->id;
}
static void
talkatu_input_set_id(TalkatuInput *input, const gchar *id) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
g_free(priv->id);
priv->id = g_strdup(id);
g_object_notify(G_OBJECT(input), "id");
}
static GDateTime *
talkatu_input_get_timestamp(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
/* If the timestamp has been explicitly set, return that. */
if(priv->timestamp != NULL) {
return priv->timestamp;
}
/* If no timestamp has been explicitly set, just return the current local
* time.
*/
return g_date_time_new_now_local();
}
static void
talkatu_input_set_timestamp(TalkatuInput *input, GDateTime *timestamp) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
g_clear_pointer(&priv->timestamp, g_date_time_unref);
if(timestamp != NULL) {
priv->timestamp = g_date_time_ref(timestamp);
}
g_object_notify(G_OBJECT(input), "timestamp");
}
static TalkatuContentType
talkatu_input_get_content_type(TalkatuInput *input) {
/* TODO: look at our buffer and map it */
return TALKATU_CONTENT_TYPE_PLAIN;
}
static void
talkatu_input_set_content_type(TalkatuInput *input,
TalkatuContentType content_type)
{
/* TODO: set the buffer here? */
g_object_notify(G_OBJECT(input), "content-type");
}
static gchar *
talkatu_input_get_author(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
return priv->author;
}
static void
talkatu_input_set_author(TalkatuInput *input, const gchar *author) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
if(author == priv->author) {
return;
}
g_clear_pointer(&priv->author, g_free);
priv->author = g_strdup(author);
g_object_notify(G_OBJECT(input), "author");
}
static GdkRGBA *
talkatu_input_get_author_name_color(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
if(priv->author_name_color != NULL) {
return gdk_rgba_copy(priv->author_name_color);
}
return NULL;
}
static void
talkatu_input_set_author_name_color(TalkatuInput *input, GdkRGBA *color) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
g_clear_pointer(&priv->author_name_color, gdk_rgba_free);
if(color != NULL) {
priv->author_name_color = gdk_rgba_copy(color);
}
g_object_notify(G_OBJECT(input), "author-name-color");
}
static gchar *
talkatu_input_get_contents(TalkatuInput *input) {
GtkTextBuffer *buffer = NULL;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(input));
return talkatu_markup_get_html(buffer, NULL);
}
static void
talkatu_input_set_contents(TalkatuInput *input, const gchar *contents) {
GtkTextBuffer *buffer = NULL;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(input));
if(contents == NULL) {
talkatu_buffer_clear(TALKATU_BUFFER(buffer));
} else {
talkatu_markup_set_html(TALKATU_BUFFER(buffer), contents, -1);
}
g_object_notify(G_OBJECT(input), "contents");
}
static gboolean
talkatu_input_get_edited(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
return priv->edited;
}
static void
talkatu_input_set_edited(TalkatuInput *input, gboolean edited) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
priv->edited = edited;
g_object_notify(G_OBJECT(input), "edited");
}
static gboolean
talkatu_input_add_attachment(TalkatuMessage *message,
TalkatuAttachment *attachment)
{
TalkatuInput *input = TALKATU_INPUT(message);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
talkatu_attachment_set_id(attachment, priv->attachment_id++);
return g_hash_table_insert(
priv->attachments,
talkatu_attachment_get_hash_key(attachment),
g_object_ref(G_OBJECT(attachment))
);
}
static gboolean
talkatu_input_remove_attachment(TalkatuMessage *message, guint64 id) {
TalkatuInput *input = TALKATU_INPUT(message);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
return g_hash_table_remove(priv->attachments, &id);
}
static TalkatuAttachment *
talkatu_input_get_attachment(TalkatuMessage *message, guint64 id) {
TalkatuInput *input = TALKATU_INPUT(message);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
TalkatuAttachment *attachment = NULL;
attachment = g_hash_table_lookup(priv->attachments, &id);
if(TALKATU_IS_ATTACHMENT(attachment)) {
return TALKATU_ATTACHMENT(g_object_ref(G_OBJECT(attachment)));
}
return NULL;
}
static void
talkatu_input_foreach_attachment_helper(gpointer key, gpointer value,
gpointer data)
{
TalkatuInputForeachAttachmentData *d = (TalkatuInputForeachAttachmentData *)data;
d->func(TALKATU_ATTACHMENT(value), d->data);
}
static void
talkatu_input_foreach_attachment(TalkatuMessage *message,
TalkatuAttachmentForeachFunc func,
gpointer data)
{
TalkatuInput *input = TALKATU_INPUT(message);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
TalkatuInputForeachAttachmentData d = {
.func = func,
.data = data
};
g_hash_table_foreach(priv->attachments,
talkatu_input_foreach_attachment_helper,
&d);
}
static void
talkatu_input_clear_attachments(TalkatuMessage *message) {
TalkatuInput *input = TALKATU_INPUT(message);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
g_hash_table_remove_all(priv->attachments);
priv->attachment_id = 0;
}
static void
talkatu_input_message_init(TalkatuMessageInterface *iface) {
iface->add_attachment = talkatu_input_add_attachment;
iface->remove_attachment = talkatu_input_remove_attachment;
iface->get_attachment = talkatu_input_get_attachment;
iface->foreach_attachment = talkatu_input_foreach_attachment;
iface->clear_attachments = talkatu_input_clear_attachments;
}
/******************************************************************************
* Callbacks
*****************************************************************************/
static void
talkatu_input_send_message_cb(GtkWidget *widget,
G_GNUC_UNUSED const gchar *action_name,
G_GNUC_UNUSED GVariant *parameter)
{
talkatu_input_send_message(TALKATU_INPUT(widget));
gtk_widget_grab_focus(widget);
}
static void
talkatu_input_should_send_message_cb(GtkWidget *widget,
G_GNUC_UNUSED const gchar *action_name,
GVariant *parameter)
{
TalkatuInput *input = TALKATU_INPUT(widget);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
TalkatuInputSendBinding binding = g_variant_get_uint32(parameter);
if((priv->send_binding & binding) != 0) {
talkatu_input_send_message(input);
} else if(gtk_text_view_get_editable(GTK_TEXT_VIEW(input))) {
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(input));
gtk_text_buffer_insert_at_cursor(buffer, "\n", 1);
}
}
static void
talkatu_input_buffer_set_cb(GObject *view, GParamSpec *pspec, gpointer data) {
TalkatuInput *input = TALKATU_INPUT(view);
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
if(TALKATU_IS_BUFFER(buffer)) {
GSimpleActionGroup *ag = NULL;
ag = talkatu_buffer_get_action_group(TALKATU_BUFFER(buffer));
if(TALKATU_IS_ACTION_GROUP(ag)) {
/* Tell the action group of the buffer that we exist. */
talkatu_action_group_set_input(TALKATU_ACTION_GROUP(ag), input);
}
}
}
static void
talkatu_input_attachment_response_cb(GtkDialog *dialog, gint response,
gpointer data)
{
/* If the user hits escape response is set to GTK_RESPONSE_DELETE_EVENT
* and Gtk cleans up the dialog for us automatically.
*/
if(response == GTK_RESPONSE_CANCEL) {
/* we call this separately for GTK_RESPONSE_CANCEL because
* GTK_RESPONSE_DELETE_EVENT already destroys the dialog.
*/
gtk_window_destroy(GTK_WINDOW(dialog));
} else if(response == GTK_RESPONSE_ACCEPT) {
GtkTextBuffer *buffer = NULL;
TalkatuAttachment *attachment = NULL;
TalkatuAttachmentDialog *adialog = TALKATU_ATTACHMENT_DIALOG(dialog);
TalkatuInput *input = TALKATU_INPUT(data);
const gchar *comment = NULL;
gchar *escaped = NULL;
comment = talkatu_attachment_dialog_get_comment(adialog);
escaped = g_markup_escape_text(comment, -1);
/* it's a pretty safe assumption that our buffer is a talkatu buffer */
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(input));
talkatu_markup_set_html(TALKATU_BUFFER(buffer), escaped, -1);
g_free(escaped);
/* now send the attachment */
attachment = talkatu_attachment_dialog_get_attachment(adialog);
talkatu_message_add_attachment(TALKATU_MESSAGE(input), attachment);
g_object_unref(G_OBJECT(attachment));
/* send the message */
talkatu_input_send_message(input);
/* kill the dialog */
gtk_window_destroy(GTK_WINDOW(dialog));
}
g_object_unref(dialog);
}
#if 0
static void
talkatu_input_image_received_cb(GtkClipboard *clipboard, GdkPixbuf *pixbuf,
gpointer data)
{
TalkatuAttachment *attachment = NULL;
GFile *file = NULL;
GFileIOStream *stream = NULL;
GOutputStream *ostream = NULL;
GtkWidget *dialog = NULL, *input = NULL;
GtkTextBuffer *buffer = NULL;
GError *error = NULL;
gchar *comment = NULL, *filename = NULL;
gboolean saved = FALSE;
guint64 size;
/* save the image on clipboard to a temp file so we can reference it in the
* attachment.
*/
file = g_file_new_tmp("talkatu-clipboard-XXXXXX.png", &stream, &error);
if(error != NULL) {
g_warning("failed to create temp file: %s", error->message);
g_error_free(error);
return;
}
ostream = g_io_stream_get_output_stream(G_IO_STREAM(stream));
saved = gdk_pixbuf_save_to_stream(pixbuf, ostream, "png", NULL, &error,
NULL);
if(!saved) {
g_object_unref(G_OBJECT(file));
g_warning("failed to save an image from the clipboard: %s",
error->message);
g_error_free(error);
g_io_stream_close(G_IO_STREAM(stream), NULL, NULL);
g_object_unref(G_OBJECT(stream));
return;
}
/* Now that all of the data has been written, use g_seekable_tell to get
* the size of the file.
*/
size = g_seekable_tell(G_SEEKABLE(ostream));
if(!g_io_stream_close(G_IO_STREAM(stream), NULL, &error)) {
g_object_unref(G_OBJECT(file));
g_warning("failed to save an image from the clipboard: %s",
error->message);
g_error_free(error);
g_object_unref(G_OBJECT(stream));
return;
}
/* now create the message and its attachment */
input = GTK_WIDGET(data);
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(input));
comment = talkatu_markup_get_html(buffer, NULL);
attachment = talkatu_simple_attachment_new(G_GUINT64_CONSTANT(0), "image/png");
filename = g_file_get_uri(file);
talkatu_attachment_set_local_uri(attachment, filename);
g_free(filename);
/* for the remote side, we'll set the filename to something
* non-descriptive.
*/
talkatu_attachment_set_remote_uri(attachment, "unknown.png");
talkatu_attachment_set_size(attachment, size);
dialog = talkatu_attachment_dialog_new(attachment, comment);
g_signal_connect(G_OBJECT(dialog), "response",
G_CALLBACK(talkatu_input_attachment_response_cb), input);
gtk_widget_show_all(dialog);
g_object_unref(G_OBJECT(file));
g_free(comment);
g_object_unref(G_OBJECT(stream));
}
#endif
/******************************************************************************
* GtkTextViewClass overrides
*****************************************************************************/
static void
talkatu_input_paste_clipboard(GtkTextView *view) {
#if 0
GdkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(view));
if(gtk_clipboard_wait_is_image_available(clipboard)) {
gtk_clipboard_request_image(clipboard, talkatu_input_image_received_cb,
view);
} else {
#endif
GTK_TEXT_VIEW_CLASS(talkatu_input_parent_class)->paste_clipboard(view);
#if 0
}
#endif
}
/******************************************************************************
* GObject Implementation
*****************************************************************************/
static void
talkatu_input_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) {
TalkatuInput *input = TALKATU_INPUT(obj);
switch(prop_id) {
case PROP_SEND_BINDING:
g_value_set_flags(value, talkatu_input_get_send_binding(input));
break;
case PROP_ID:
g_value_set_string(value, talkatu_input_get_id(input));
break;
case PROP_TIMESTAMP:
g_value_set_boxed(value, talkatu_input_get_timestamp(input));
break;
case PROP_CONTENT_TYPE:
g_value_set_enum(value, talkatu_input_get_content_type(input));
break;
case PROP_AUTHOR:
g_value_set_string(value, talkatu_input_get_author(input));
break;
case PROP_AUTHOR_NAME_COLOR:
g_value_set_boxed(value, talkatu_input_get_author_name_color(input));
break;
case PROP_CONTENTS:
g_value_set_string(value, talkatu_input_get_contents(input));
break;
case PROP_EDITED:
g_value_set_boolean(value, talkatu_input_get_edited(input));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
}
}
static void
talkatu_input_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) {
TalkatuInput *input = TALKATU_INPUT(obj);
switch(prop_id) {
case PROP_SEND_BINDING:
talkatu_input_set_send_binding(input, g_value_get_flags(value));
break;
case PROP_ID:
talkatu_input_set_id(input, g_value_get_string(value));
break;
case PROP_TIMESTAMP:
talkatu_input_set_timestamp(input, g_value_get_boxed(value));
break;
case PROP_CONTENT_TYPE:
talkatu_input_set_content_type(input, g_value_get_enum(value));
break;
case PROP_AUTHOR:
talkatu_input_set_author(input, g_value_get_string(value));
break;
case PROP_AUTHOR_NAME_COLOR:
talkatu_input_set_author_name_color(input, g_value_get_boxed(value));
break;
case PROP_CONTENTS:
talkatu_input_set_contents(input, g_value_get_string(value));
break;
case PROP_EDITED:
talkatu_input_set_edited(input, g_value_get_boolean(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
}
}
static void
talkatu_input_init(TalkatuInput *input) {
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
gtk_widget_init_template(GTK_WIDGET(input));
priv->attachments = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_object_unref);
}
static void
talkatu_input_finalize(GObject *obj) {
TalkatuInput *input = TALKATU_INPUT(obj);
TalkatuInputPrivate *priv = talkatu_input_get_instance_private(input);
g_hash_table_destroy(priv->attachments);
g_clear_pointer(&priv->timestamp, g_date_time_unref);
g_clear_pointer(&priv->author, g_free);
g_clear_pointer(&priv->author_name_color, gdk_rgba_free);
G_OBJECT_CLASS(talkatu_input_parent_class)->finalize(obj);
}
static void
talkatu_input_class_init(TalkatuInputClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
GtkTextViewClass *text_view_class = GTK_TEXT_VIEW_CLASS(klass);
obj_class->get_property = talkatu_input_get_property;
obj_class->set_property = talkatu_input_set_property;
obj_class->finalize = talkatu_input_finalize;
text_view_class->paste_clipboard = talkatu_input_paste_clipboard;
/* add our properties */
properties[PROP_SEND_BINDING] = g_param_spec_flags(
"send-binding", "send-binding",
"The keybindings that will trigger the send signal",
TALKATU_TYPE_INPUT_SEND_BINDING,
TALKATU_INPUT_SEND_BINDING_RETURN | TALKATU_INPUT_SEND_BINDING_KP_ENTER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT
);
g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
/* override the properties for the interface */
g_object_class_override_property(obj_class, PROP_ID, "id");
g_object_class_override_property(obj_class, PROP_TIMESTAMP, "timestamp");
g_object_class_override_property(obj_class, PROP_CONTENT_TYPE, "content-type");
g_object_class_override_property(obj_class, PROP_AUTHOR, "author");
g_object_class_override_property(obj_class, PROP_AUTHOR_NAME_COLOR, "author-name-color");
g_object_class_override_property(obj_class, PROP_CONTENTS, "contents");
g_object_class_override_property(obj_class, PROP_EDITED, "edited");
/**
* TalkatuInput::send-message:
* @talkatuinput: The #TalkatuInput instance.
* @user_data: User supplied data.
*
* Emitted when a message should be sent.
*/
signals[SIG_SEND_MESSAGE] = g_signal_new(
"send-message",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET(TalkatuInputClass, send_message),
NULL,
NULL,
NULL,
G_TYPE_NONE,
0
);
/* Setup actions */
gtk_widget_class_install_action(widget_class, "message.send", NULL,
talkatu_input_send_message_cb);
gtk_widget_class_install_action(widget_class, "message.should-send", NULL,
talkatu_input_should_send_message_cb);
/* Template setup */
gtk_widget_class_set_template_from_resource(
widget_class,
"/org/imfreedom/keep/talkatu/talkatu/ui/input.ui"
);
gtk_widget_class_bind_template_callback(widget_class,
talkatu_input_buffer_set_cb);
/* setup key bindings */
gtk_widget_class_add_binding_action(widget_class,
GDK_KEY_Return, 0,
"message.should-send", "u",
TALKATU_INPUT_SEND_BINDING_RETURN);
gtk_widget_class_add_binding_action(widget_class,
GDK_KEY_Return, GDK_SHIFT_MASK,
"message.should-send", "u",
TALKATU_INPUT_SEND_BINDING_SHIFT_RETURN);
gtk_widget_class_add_binding_action(widget_class,
GDK_KEY_Return, GDK_CONTROL_MASK,
"message.should-send", "u",
TALKATU_INPUT_SEND_BINDING_CONTROL_RETURN);
gtk_widget_class_add_binding_action(widget_class,
GDK_KEY_KP_Enter, 0,
"message.should-send", "u",
TALKATU_INPUT_SEND_BINDING_KP_ENTER);
}
/******************************************************************************
* Public API
*****************************************************************************/
/**
* talkatu_input_new:
*
* Creates a new #TalkatuInput instance.
*
* Returns: (transfer full): The new #TalkatuInput instance.
*/
GtkWidget *
talkatu_input_new(void) {
return g_object_new(TALKATU_TYPE_INPUT, NULL);
}
/**
* talkatu_input_set_send_binding:
* @input: The #TalkatuInput instance.
* @bindings: The #TalkatuInputSendBinding value.
*
* Sets the bindings for when the send-message signal should be emitted.
*/
void
talkatu_input_set_send_binding(TalkatuInput *input,
TalkatuInputSendBinding bindings)
{
TalkatuInputPrivate *priv = NULL;
g_return_if_fail(TALKATU_IS_INPUT(input));
priv = talkatu_input_get_instance_private(input);
priv->send_binding = bindings;
g_object_notify_by_pspec(G_OBJECT(input), properties[PROP_SEND_BINDING]);
}
/**
* talkatu_input_get_send_binding:
* @input: The #TalkatuInput instance.
*
* Gets the #TalkatuInputSendBinding which determines when send-message
* signal will be emitted.
*
* Returns: The #TalkatuInputSendBinding.
*/
TalkatuInputSendBinding
talkatu_input_get_send_binding(TalkatuInput *input) {
TalkatuInputPrivate *priv = NULL;
g_return_val_if_fail(TALKATU_IS_INPUT(input), 0);
priv = talkatu_input_get_instance_private(input);
return priv->send_binding;
}
/**
* talkatu_input_send_message:
* @input: The #TalkatuInput instance.
*
* Emits the signal that @input is trying to send a message. This is used for
* cases like the optional send button in #TalkatuEditor and other instances
* where the user has performed an action to send a message.
*/
void
talkatu_input_send_message(TalkatuInput *input) {
g_return_if_fail(TALKATU_IS_INPUT(input));
g_signal_emit(input, signals[SIG_SEND_MESSAGE], 0);
}