qulogic/talkatu
Clone
Summary
Browse
Changes
Graph
Somehow maiku was missing, so I added him
2019-08-05, Gary Kramlich
2e691dcd9200
Somehow maiku was missing, so I added him
/*
* talkatu
* Copyright (C) 2017-2019 Gary Kramlich <grim@reaperworld.com>
*
* 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
<glib/gi18n-lib.h>
#include
<gtk/gtk.h>
#include
<gdk/gdkkeysyms.h>
#include
<gspell/gspell.h>
#include
<gumbo.h>
#include
<stdio.h>
#include
"talkatu/talkatuactiongroup.h"
#include
"talkatu/talkatubuffer.h"
#include
"talkatu/talkatuenums.h"
#include
"talkatu/talkatutag.h"
#include
"talkatu/talkatuview.h"
/**
* SECTION:talkatuview
* @Title: Text View
* @Short_description: Widget that displays a TalkatuBuffer
*
* #TalkatuView handles the display of a #TalkatuBuffer, the keybindings for
* applying formats, as well as displaying links.
*/
/**
* TALKATU_TYPE_VIEW:
*
* The standard _get_type macro for #TalkatuView.
*/
/**
* TalkatuViewClass:
* @format_activate: The class handler for the #TalkatuView::format_activate
* signal.
* @should_send_message: The class handler for the
* #TalkatuView::should_send_message signal.
* @send_message: The class handler for the #TalkatuView::send_message signal.
* @open_url: The class handler for the #TalkatuView::open_url signal.
*
* The backing class to #TalkatuView instances.
*/
/**
* TalkatuViewSendBinding:
* @TALKATU_VIEW_SEND_BINDING_RETURN: Represents return.
* @TALKATU_VIEW_SEND_BINDING_KP_ENTER: Represents enter.
* @TALKATU_VIEW_SEND_BINDING_SHIFT_RETURN: Represents shift-return.
* @TALKATU_VIEW_SEND_BINDING_CONTROL_RETURN: Represents control-return.
*
* Flags for assigning and determining which key bindings should be used to
* send a message.
*/
/**
* TalkatuView:
*
* A #GtkTextView subclass that's preconfigured with a #TalkatuBuffer.
*/
typedef
struct
{
GSimpleActionGroup
*
action_group
;
TalkatuViewSendBinding
send_binding
;
GspellTextView
*
gspell_view
;
/* this mark is used to keep track of our context for the context menu. It
* is updated via cursor-moved and button-press callbacks.
*/
GtkTextMark
*
context_mark
;
/* we cache the cursor that's displayed while hovering over a link as well
* the tag for links/anchors to avoid extra lookups.
*/
GdkCursor
*
cursor_hand
;
GtkTextTag
*
tag_anchor
;
}
TalkatuViewPrivate
;
enum
{
PROP_0
=
0
,
PROP_SEND_BINDING
,
N_PROPERTIES
,
};
static
GParamSpec
*
properties
[
N_PROPERTIES
];
enum
{
SIG_FORMAT_ACTIVATE
,
SIG_SHOULD_SEND_MESSAGE
,
SIG_SEND_MESSAGE
,
SIG_OPEN_URL
,
LAST_SIGNAL
,
};
static
guint
signals
[
LAST_SIGNAL
]
=
{
0
,
};
G_DEFINE_TYPE_WITH_PRIVATE
(
TalkatuView
,
talkatu_view
,
GTK_TYPE_TEXT_VIEW
)
/******************************************************************************
* Helpers
*****************************************************************************/
static
gchar
*
talkatu_view_url_from_iter
(
TalkatuView
*
view
,
GtkTextIter
*
iter
)
{
GSList
*
tag
=
NULL
;
gchar
*
url
=
NULL
;
tag
=
gtk_text_iter_get_tags
(
iter
);
for
(;
tag
!=
NULL
;
tag
=
g_slist_delete_link
(
tag
,
tag
))
{
if
(
tag
->
data
==
NULL
)
{
continue
;
}
url
=
g_object_get_data
(
G_OBJECT
(
tag
->
data
),
"talkatu-anchor-url"
);
if
(
url
!=
NULL
)
{
break
;
}
}
g_slist_free
(
tag
);
return
url
;
}
/******************************************************************************
* Callbacks
*****************************************************************************/
static
void
talkatu_view_open_url_cb
(
GtkMenuItem
*
item
,
gpointer
data
)
{
TalkatuView
*
view
=
g_object_get_data
(
G_OBJECT
(
item
),
"view"
);
gchar
*
url
=
g_object_get_data
(
G_OBJECT
(
item
),
"url"
);
g_signal_emit
(
view
,
signals
[
SIG_OPEN_URL
],
0
,
url
);
}
static
void
talkatu_view_copy_url_cb
(
GtkMenuItem
*
item
,
gpointer
data
)
{
GtkClipboard
*
clipboard
=
gtk_widget_get_clipboard
(
GTK_WIDGET
(
item
),
GDK_SELECTION_CLIPBOARD
);
gtk_clipboard_set_text
(
clipboard
,
(
gchar
*
)
data
,
-1
);
}
gboolean
talkatu_view_anchor_tag_event_cb
(
GtkTextTag
*
tag
,
GObject
*
object
,
GdkEvent
*
event
,
GtkTextIter
*
iter
,
gpointer
data
)
{
GdkEventType
event_type
=
gdk_event_get_event_type
(
event
);
if
(
event_type
==
GDK_BUTTON_PRESS
)
{
GdkEventButton
*
event_button
=
(
GdkEventButton
*
)
event
;
/* the user is right clicking on a link so stop the default handler */
if
(
event_button
->
button
==
GDK_BUTTON_SECONDARY
)
{
return
TRUE
;
}
}
else
if
(
gdk_event_triggers_context_menu
(
event
))
{
GdkEventButton
*
event_button
=
(
GdkEventButton
*
)
event
;
TalkatuView
*
view
=
TALKATU_VIEW
(
object
);
gchar
*
url
;
url
=
talkatu_view_url_from_iter
(
view
,
iter
);
/* if we didn't find a url, bail */
if
(
url
==
NULL
)
{
return
FALSE
;
}
if
(
event_button
->
button
==
GDK_BUTTON_PRIMARY
)
{
GtkTextBuffer
*
buffer
=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
view
));
/* old behavior from pidgin2, if the users has something selected
* we don't open links. Other clients don't do this.. but it seems
* to be a work around for someone pressing a button over text,
* then moving the cursor to the link and then releasing. Without
* the selection check that'll cause that to open the link if the
* button is released in the middle of the link.
*/
if
(
gtk_text_buffer_get_has_selection
(
buffer
))
{
return
FALSE
;
}
g_signal_emit
(
view
,
signals
[
SIG_OPEN_URL
],
0
,
url
);
return
TRUE
;
}
else
if
(
gdk_event_triggers_context_menu
(
event
))
{
GtkWidget
*
menu
=
gtk_menu_new
();
GtkWidget
*
item
=
NULL
;
item
=
gtk_menu_item_new_with_label
(
_
(
"Open Link"
));
/* to make it easier to deal with the life cycle, we just add data
* to the menu item itself with destroy notifies.
*/
g_object_set_data_full
(
G_OBJECT
(
item
),
"view"
,
g_object_ref
(
view
),
g_object_unref
);
g_object_set_data_full
(
G_OBJECT
(
item
),
"url"
,
g_strdup
(
url
),
g_free
);
g_signal_connect
(
G_OBJECT
(
item
),
"activate"
,
G_CALLBACK
(
talkatu_view_open_url_cb
),
NULL
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
menu
),
item
);
item
=
gtk_menu_item_new_with_label
(
_
(
"Copy Link"
));
g_signal_connect
(
G_OBJECT
(
item
),
"activate"
,
G_CALLBACK
(
talkatu_view_copy_url_cb
),
url
);
gtk_menu_shell_append
(
GTK_MENU_SHELL
(
menu
),
item
);
gtk_widget_show_all
(
menu
);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_menu_popup
(
GTK_MENU
(
menu
),
NULL
,
NULL
,
NULL
,
NULL
,
0
,
event_button
->
time
);
G_GNUC_END_IGNORE_DEPRECATIONS
return
TRUE
;
}
}
return
FALSE
;
}
static
void
talkatu_view_buffer_set_cb
(
GObject
*
view
,
GParamSpec
*
pspec
,
gpointer
data
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
TALKATU_VIEW
(
view
));
GtkTextBuffer
*
buffer
=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
view
));
GtkTextTagTable
*
table
=
gtk_text_buffer_get_tag_table
(
buffer
);
GtkTextIter
start
;
if
(
TALKATU_IS_BUFFER
(
buffer
))
{
priv
->
action_group
=
talkatu_buffer_get_action_group
(
TALKATU_BUFFER
(
buffer
));
}
gtk_text_buffer_get_start_iter
(
buffer
,
&
start
);
priv
->
context_mark
=
gtk_text_buffer_create_mark
(
buffer
,
NULL
,
&
start
,
TRUE
);
/* check for the anchor tag, if we have it, add a signal handler to it */
priv
->
tag_anchor
=
gtk_text_tag_table_lookup
(
table
,
TALKATU_TAG_ANCHOR
);
if
(
priv
->
tag_anchor
!=
NULL
)
{
g_signal_connect
(
priv
->
tag_anchor
,
"event"
,
G_CALLBACK
(
talkatu_view_anchor_tag_event_cb
),
NULL
);
}
gspell_text_view_basic_setup
(
priv
->
gspell_view
);
}
/******************************************************************************
* Default Signal Handlers
*****************************************************************************/
static
void
talkatu_view_format_activate
(
TalkatuView
*
view
,
const
gchar
*
action_name
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
view
);
if
(
priv
->
action_group
)
{
GAction
*
action
=
g_action_map_lookup_action
(
G_ACTION_MAP
(
priv
->
action_group
),
action_name
);
if
(
action
)
{
g_action_activate
(
action
,
NULL
);
}
}
}
static
void
talkatu_view_should_send_message
(
TalkatuView
*
view
,
TalkatuViewSendBinding
binding
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
view
);
if
((
priv
->
send_binding
&
binding
)
!=
0
)
{
talkatu_view_send_message
(
view
);
}
else
if
(
gtk_text_view_get_editable
(
GTK_TEXT_VIEW
(
view
)))
{
GtkTextBuffer
*
buffer
=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
view
));
gtk_text_buffer_insert_at_cursor
(
buffer
,
"
\n
"
,
1
);
}
}
static
gboolean
talkatu_view_popup_menu
(
GtkWidget
*
widget
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
TALKATU_VIEW
(
widget
));
GtkTextBuffer
*
buffer
=
NULL
;
GtkTextIter
iter
;
buffer
=
gtk_text_view_get_buffer
(
GTK_TEXT_VIEW
(
widget
));
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
iter
,
gtk_text_buffer_get_insert
(
buffer
)
);
gtk_text_buffer_move_mark
(
buffer
,
priv
->
context_mark
,
&
iter
);
return
GTK_WIDGET_CLASS
(
talkatu_view_parent_class
)
->
popup_menu
(
widget
);
}
static
void
talkatu_view_send_message_cb
(
GtkMenuItem
*
item
,
gpointer
data
)
{
talkatu_view_send_message
(
TALKATU_VIEW
(
data
));
gtk_widget_grab_focus
(
GTK_WIDGET
(
data
));
}
static
void
talkatu_view_populate_popup_cb
(
GtkTextView
*
view
,
GtkWidget
*
popup
)
{
TalkatuViewPrivate
*
priv
=
NULL
;
GtkTextBuffer
*
buffer
=
NULL
;
GtkTextIter
iter
;
GtkWidget
*
item
=
NULL
;
gint
pos
=
0
;
/* if the popup isn't a menu, bail */
if
(
!
GTK_IS_MENU
(
popup
))
{
return
;
}
priv
=
talkatu_view_get_instance_private
(
TALKATU_VIEW
(
view
));
buffer
=
gtk_text_view_get_buffer
(
view
);
gtk_text_buffer_get_iter_at_mark
(
buffer
,
&
iter
,
priv
->
context_mark
);
/* add the send message item */
if
(
gtk_text_view_get_editable
(
view
))
{
item
=
gtk_menu_item_new_with_label
(
_
(
"Send message"
));
g_signal_connect_after
(
G_OBJECT
(
item
),
"activate"
,
G_CALLBACK
(
talkatu_view_send_message_cb
),
view
);
gtk_menu_shell_insert
(
GTK_MENU_SHELL
(
popup
),
item
,
pos
++
);
gtk_widget_show
(
item
);
item
=
gtk_separator_menu_item_new
();
gtk_menu_shell_insert
(
GTK_MENU_SHELL
(
popup
),
item
,
pos
++
);
gtk_widget_show
(
item
);
}
}
static
gboolean
talkatu_view_query_tooltip
(
GtkWidget
*
widget
,
gint
x
,
gint
y
,
gboolean
keyboard
,
GtkTooltip
*
tooltip
)
{
GtkTextIter
iter
;
gchar
*
url
=
NULL
;
gint
adj_x
,
adj_y
;
if
(
keyboard
)
{
return
GTK_WIDGET_CLASS
(
talkatu_view_parent_class
)
->
query_tooltip
(
widget
,
x
,
y
,
keyboard
,
tooltip
);
}
/* convert the window coordinates to match whats visible */
gtk_text_view_window_to_buffer_coords
(
GTK_TEXT_VIEW
(
widget
),
GTK_TEXT_WINDOW_TEXT
,
x
,
y
,
&
adj_x
,
&
adj_y
);
/* now find the iter for what we're at */
gtk_text_view_get_iter_at_location
(
GTK_TEXT_VIEW
(
widget
),
&
iter
,
adj_x
,
adj_y
);
/* look for a url, if we have one, add it to tooltip */
url
=
talkatu_view_url_from_iter
(
TALKATU_VIEW
(
widget
),
&
iter
);
if
(
url
!=
NULL
)
{
gtk_tooltip_set_text
(
tooltip
,
url
);
return
TRUE
;
}
return
GTK_WIDGET_CLASS
(
talkatu_view_parent_class
)
->
query_tooltip
(
widget
,
x
,
y
,
keyboard
,
tooltip
);
}
static
gboolean
talkatu_view_motion_notify_event
(
GtkWidget
*
widget
,
GdkEventMotion
*
event
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
TALKATU_VIEW
(
widget
));
GtkTextIter
iter
;
GdkCursor
*
cursor
=
NULL
;
gint
x
,
y
;
gtk_text_view_window_to_buffer_coords
(
GTK_TEXT_VIEW
(
widget
),
GTK_TEXT_WINDOW_TEXT
,
event
->
x
,
event
->
y
,
&
x
,
&
y
);
gtk_text_view_get_iter_at_location
(
GTK_TEXT_VIEW
(
widget
),
&
iter
,
x
,
y
);
if
(
gtk_text_iter_has_tag
(
&
iter
,
priv
->
tag_anchor
))
{
cursor
=
priv
->
cursor_hand
;
}
if
(
cursor
!=
gdk_window_get_cursor
(
event
->
window
))
{
gdk_window_set_cursor
(
event
->
window
,
cursor
);
return
TRUE
;
}
return
GTK_WIDGET_CLASS
(
talkatu_view_parent_class
)
->
motion_notify_event
(
widget
,
event
);
}
/******************************************************************************
* GtkTextViewClass overrides
*****************************************************************************/
static
GtkTextBuffer
*
talkatu_view_create_buffer
(
GtkTextView
*
view
)
{
return
talkatu_buffer_new
(
NULL
);
}
/******************************************************************************
* GObject Stuff
*****************************************************************************/
static
void
talkatu_view_finalize
(
GObject
*
obj
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
TALKATU_VIEW
(
obj
));
g_clear_object
(
&
priv
->
cursor_hand
);
G_OBJECT_CLASS
(
talkatu_view_parent_class
)
->
finalize
(
obj
);
}
static
void
talkatu_view_get_property
(
GObject
*
obj
,
guint
prop_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
TalkatuView
*
view
=
TALKATU_VIEW
(
obj
);
switch
(
prop_id
)
{
case
PROP_SEND_BINDING
:
g_value_set_flags
(
value
,
talkatu_view_get_send_binding
(
view
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
prop_id
,
pspec
);
break
;
}
}
static
void
talkatu_view_set_property
(
GObject
*
obj
,
guint
prop_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
TalkatuView
*
view
=
TALKATU_VIEW
(
obj
);
switch
(
prop_id
)
{
case
PROP_SEND_BINDING
:
talkatu_view_set_send_binding
(
view
,
g_value_get_flags
(
value
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
prop_id
,
pspec
);
break
;
}
}
static
void
talkatu_view_init
(
TalkatuView
*
view
)
{
TalkatuViewPrivate
*
priv
=
talkatu_view_get_instance_private
(
view
);
priv
->
cursor_hand
=
gdk_cursor_new_from_name
(
gdk_display_get_default
(),
"pointer"
);
/* tell the widget class that we support tooltips. This is used to show
* link targets, and probably other stuff at some point.
*/
gtk_widget_set_has_tooltip
(
GTK_WIDGET
(
view
),
TRUE
);
/* set our event mask for the signals we care about */
gtk_widget_set_events
(
GTK_WIDGET
(
view
),
GDK_BUTTON_RELEASE_MASK
|
GDK_POINTER_MOTION_MASK
);
/* we need to know when the buffer is changed in our parent so we can
* update our actions and other stuff.
*/
g_signal_connect
(
G_OBJECT
(
view
),
"notify::buffer"
,
G_CALLBACK
(
talkatu_view_buffer_set_cb
),
NULL
);
/* setup GSpell */
priv
->
gspell_view
=
gspell_text_view_get_from_gtk_text_view
(
GTK_TEXT_VIEW
(
view
));
/* we need to connect this signal *AFTER* everything to make sure our items
* end up in the correct place.
*/
g_signal_connect_after
(
G_OBJECT
(
view
),
"populate-popup"
,
G_CALLBACK
(
talkatu_view_populate_popup_cb
),
NULL
);
}
static
void
talkatu_view_class_init
(
TalkatuViewClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
GtkWidgetClass
*
widget_class
=
GTK_WIDGET_CLASS
(
klass
);
GtkTextViewClass
*
text_view_class
=
GTK_TEXT_VIEW_CLASS
(
klass
);
GtkBindingSet
*
binding_set
=
NULL
;
obj_class
->
get_property
=
talkatu_view_get_property
;
obj_class
->
set_property
=
talkatu_view_set_property
;
obj_class
->
finalize
=
talkatu_view_finalize
;
widget_class
->
motion_notify_event
=
talkatu_view_motion_notify_event
;
widget_class
->
popup_menu
=
talkatu_view_popup_menu
;
widget_class
->
query_tooltip
=
talkatu_view_query_tooltip
;
text_view_class
->
create_buffer
=
talkatu_view_create_buffer
;
/* add our default signal handlers */
klass
->
format_activate
=
talkatu_view_format_activate
;
klass
->
should_send_message
=
talkatu_view_should_send_message
;
/* 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_VIEW_SEND_BINDING
,
TALKATU_VIEW_SEND_BINDING_RETURN
|
TALKATU_VIEW_SEND_BINDING_KP_ENTER
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
);
g_object_class_install_properties
(
obj_class
,
N_PROPERTIES
,
properties
);
/* add our signals */
/**
* TalkatuView::format-activate
* @talkatutextview: The #TalkatuView instance.
* @arg1: The name of the action to activated.
* @user_data: User supplied data.
*
* Emitted by the keybindings to apply a format to the underlying buffer.
*/
signals
[
SIG_FORMAT_ACTIVATE
]
=
g_signal_new
(
"format-activate"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
|
G_SIGNAL_ACTION
,
G_STRUCT_OFFSET
(
TalkatuViewClass
,
format_activate
),
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
1
,
G_TYPE_STRING
);
/**
* TalkatuView::should-send-message:
* @talkatutextview: The #TalkatuView instance.
* @arg1: The #TalkatuViewSendBinding that was entered.
* @user_data: User supplied data.
*
* Emitted when a potential keybinding to send the message is entered to
* determine if the message should be sent.
*/
signals
[
SIG_SHOULD_SEND_MESSAGE
]
=
g_signal_new
(
"should-send-message"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
|
G_SIGNAL_ACTION
,
G_STRUCT_OFFSET
(
TalkatuViewClass
,
should_send_message
),
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
1
,
TALKATU_TYPE_VIEW_SEND_BINDING
);
/**
* TalkatuView::send-message:
* @talkatutextview: The #TalkatuView 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
(
TalkatuViewClass
,
send_message
),
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
0
);
/**
* TalkatuView::open-url:
* @talkatutextview: The #TalkatuView instances.
* @url: The URL to open.
* @user_data: User supplied data.
*
* Emitted when a user clicks on a link to open the url
*/
signals
[
SIG_OPEN_URL
]
=
g_signal_new
(
"open-url"
,
G_TYPE_FROM_CLASS
(
klass
),
G_SIGNAL_RUN_LAST
|
G_SIGNAL_ACTION
,
G_STRUCT_OFFSET
(
TalkatuViewClass
,
open_url
),
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
1
,
G_TYPE_STRING
);
/* setup key bindings */
binding_set
=
gtk_binding_set_by_class
(
talkatu_view_parent_class
);
/* remove existing keybindings that we're overriding */
gtk_binding_entry_remove
(
binding_set
,
GDK_KEY_slash
,
GDK_CONTROL_MASK
);
/* add our custom keybindings */
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_b
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_BOLD
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_i
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_ITALIC
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_u
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_UNDERLINE
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_slash
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_STRIKETHROUGH
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_plus
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_GROW
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_equal
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_GROW
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_minus
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_SHRINK
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_r
,
GDK_CONTROL_MASK
,
"format-activate"
,
1
,
G_TYPE_STRING
,
TALKATU_ACTION_FORMAT_RESET
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_Return
,
0
,
"should-send-message"
,
1
,
TALKATU_TYPE_VIEW_SEND_BINDING
,
TALKATU_VIEW_SEND_BINDING_RETURN
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_Return
,
GDK_SHIFT_MASK
,
"should-send-message"
,
1
,
TALKATU_TYPE_VIEW_SEND_BINDING
,
TALKATU_VIEW_SEND_BINDING_SHIFT_RETURN
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_Return
,
GDK_CONTROL_MASK
,
"should-send-message"
,
1
,
TALKATU_TYPE_VIEW_SEND_BINDING
,
TALKATU_VIEW_SEND_BINDING_CONTROL_RETURN
);
gtk_binding_entry_add_signal
(
binding_set
,
GDK_KEY_KP_Enter
,
0
,
"should-send-message"
,
1
,
TALKATU_TYPE_VIEW_SEND_BINDING
,
TALKATU_VIEW_SEND_BINDING_KP_ENTER
);
}
/******************************************************************************
* Public API
*****************************************************************************/
/**
* talkatu_view_new:
*
* Creates a new #TalkatuView with a #TalkatuBuffer.
*
* Returns: (transfer full): The new #TalkatuView.
*/
GtkWidget
*
talkatu_view_new
(
void
)
{
return
talkatu_view_new_with_buffer
(
talkatu_buffer_new
(
NULL
));
}
/**
* talkatu_view_new_with_buffer:
* @buffer: A #GtkTextBuffer.
*
* Creates a new #TalkatuView with @buffer.
*
* Returns: (transfer full): The new #TalkatuView.
*/
GtkWidget
*
talkatu_view_new_with_buffer
(
GtkTextBuffer
*
buffer
)
{
return
GTK_WIDGET
(
g_object_new
(
TALKATU_TYPE_VIEW
,
"buffer"
,
buffer
,
NULL
));
}
/**
* talkatu_view_set_send_binding:
* @view: The #TalkatuView instance.
* @bindings: The #TalkatuViewSendBinding value.
*
* Sets the bindings for when the send-message signal should be emitted.
*/
void
talkatu_view_set_send_binding
(
TalkatuView
*
view
,
TalkatuViewSendBinding
bindings
)
{
TalkatuViewPrivate
*
priv
=
NULL
;
g_return_if_fail
(
TALKATU_IS_VIEW
(
view
));
priv
=
talkatu_view_get_instance_private
(
view
);
priv
->
send_binding
=
bindings
;
g_object_notify_by_pspec
(
G_OBJECT
(
view
),
properties
[
PROP_SEND_BINDING
]);
}
/**
* talkatu_view_get_send_binding:
* @view: The #TalkatuView instance.
*
* Gets the #TalkatuViewSendBinding which determines when send-message
* signal will be emitted.
*
* Returns: The #TalkatuViewSendBinding.
*/
TalkatuViewSendBinding
talkatu_view_get_send_binding
(
TalkatuView
*
view
)
{
TalkatuViewPrivate
*
priv
=
NULL
;
g_return_val_if_fail
(
TALKATU_IS_VIEW
(
view
),
0
);
priv
=
talkatu_view_get_instance_private
(
view
);
return
priv
->
send_binding
;
}
/**
* talkatu_view_send_message:
* @view: The #TalkatuView instance.
*
* Emits the signal that @view 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_view_send_message
(
TalkatuView
*
view
)
{
g_return_if_fail
(
TALKATU_IS_VIEW
(
view
));
g_signal_emit
(
view
,
signals
[
SIG_SEND_MESSAGE
],
0
);
}