812 lines
23 KiB
C
812 lines
23 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <gtk/gtk.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
#include <libpeas/peas-extension-set.h>
|
|
#include <glib/gi18n.h>
|
|
|
|
#include "xed-view.h"
|
|
#include "xed-view-gutter-renderer.h"
|
|
#include "xed-view-activatable.h"
|
|
#include "xed-plugins-engine.h"
|
|
#include "xed-debug.h"
|
|
#include "xed-marshal.h"
|
|
#include "xed-utils.h"
|
|
#include "xed-settings.h"
|
|
#include "xed-app.h"
|
|
|
|
#define XED_VIEW_SCROLL_MARGIN 0.02
|
|
|
|
#define XED_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_VIEW, XedViewPrivate))
|
|
|
|
enum
|
|
{
|
|
TARGET_URI_LIST = 100
|
|
};
|
|
|
|
struct _XedViewPrivate
|
|
{
|
|
GSettings *editor_settings;
|
|
GtkTextBuffer *current_buffer;
|
|
PeasExtensionSet *extensions;
|
|
GtkSourceGutterRenderer *renderer;
|
|
guint view_realized : 1;
|
|
};
|
|
|
|
G_DEFINE_TYPE (XedView, xed_view, GTK_SOURCE_TYPE_VIEW)
|
|
|
|
/* Signals */
|
|
enum
|
|
{
|
|
DROP_URIS,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint view_signals[LAST_SIGNAL] = { 0 };
|
|
|
|
static void
|
|
document_read_only_notify_handler (XedDocument *document,
|
|
GParamSpec *pspec,
|
|
XedView *view)
|
|
{
|
|
xed_debug (DEBUG_VIEW);
|
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (document));
|
|
}
|
|
|
|
static void
|
|
current_buffer_removed (XedView *view)
|
|
{
|
|
if (view->priv->current_buffer != NULL)
|
|
{
|
|
g_signal_handlers_disconnect_by_func(view->priv->current_buffer, document_read_only_notify_handler, view);
|
|
g_object_unref (view->priv->current_buffer);
|
|
view->priv->current_buffer = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
extension_added (PeasExtensionSet *extensions,
|
|
PeasPluginInfo *info,
|
|
PeasExtension *exten,
|
|
XedView *view)
|
|
{
|
|
peas_extension_call (exten, "activate");
|
|
}
|
|
|
|
static void
|
|
extension_removed (PeasExtensionSet *extensions,
|
|
PeasPluginInfo *info,
|
|
PeasExtension *exten,
|
|
XedView *view)
|
|
{
|
|
peas_extension_call (exten, "deactivate");
|
|
}
|
|
|
|
static void
|
|
on_notify_buffer_cb (XedView *view,
|
|
GParamSpec *arg1,
|
|
gpointer userdata)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
|
|
current_buffer_removed (view);
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
|
|
|
|
if (buffer == NULL || !XED_IS_DOCUMENT (buffer))
|
|
{
|
|
return;
|
|
}
|
|
|
|
view->priv->current_buffer = g_object_ref (buffer);
|
|
g_signal_connect(buffer, "notify::read-only", G_CALLBACK (document_read_only_notify_handler), view);
|
|
|
|
gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
|
}
|
|
|
|
static void
|
|
xed_view_init (XedView *view)
|
|
{
|
|
GtkTargetList *tl;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
view->priv = XED_VIEW_GET_PRIVATE (view);
|
|
|
|
view->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
|
|
|
|
/* Drag and drop support */
|
|
tl = gtk_drag_dest_get_target_list (GTK_WIDGET(view));
|
|
|
|
if (tl != NULL)
|
|
{
|
|
gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST);
|
|
}
|
|
|
|
view->priv->extensions = peas_extension_set_new (PEAS_ENGINE (xed_plugins_engine_get_default ()),
|
|
XED_TYPE_VIEW_ACTIVATABLE, "view", view, NULL);
|
|
|
|
g_signal_connect (view->priv->extensions, "extension-added",
|
|
G_CALLBACK (extension_added), view);
|
|
g_signal_connect (view->priv->extensions, "extension-removed",
|
|
G_CALLBACK (extension_removed), view);
|
|
|
|
/* Act on buffer change */
|
|
g_signal_connect(view, "notify::buffer", G_CALLBACK (on_notify_buffer_cb), NULL);
|
|
}
|
|
|
|
static void
|
|
xed_view_dispose (GObject *object)
|
|
{
|
|
XedView *view = XED_VIEW (object);
|
|
|
|
g_clear_object (&view->priv->extensions);
|
|
g_clear_object (&view->priv->editor_settings);
|
|
g_clear_object (&view->priv->renderer);
|
|
|
|
current_buffer_removed (view);
|
|
|
|
/* Disconnect notify buffer because the destroy of the textview will set
|
|
* the buffer to NULL, and we call get_buffer in the notify which would
|
|
* reinstate a buffer which we don't want.
|
|
* There is no problem calling g_signal_handlers_disconnect_by_func()
|
|
* several times (if dispose() is called several times).
|
|
*/
|
|
g_signal_handlers_disconnect_by_func (view, on_notify_buffer_cb, NULL);
|
|
|
|
G_OBJECT_CLASS (xed_view_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
xed_view_constructed (GObject *object)
|
|
{
|
|
XedView *view;
|
|
XedViewPrivate *priv;
|
|
gboolean use_default_font;
|
|
GtkSourceGutter *gutter;
|
|
|
|
view = XED_VIEW (object);
|
|
priv = view->priv;
|
|
|
|
/* Get setting values */
|
|
use_default_font = g_settings_get_boolean (view->priv->editor_settings, XED_SETTINGS_USE_DEFAULT_FONT);
|
|
|
|
/*
|
|
* Set tab, fonts, wrap mode, colors, etc. according to preferences
|
|
*/
|
|
if (!use_default_font)
|
|
{
|
|
gchar *editor_font;
|
|
|
|
editor_font = g_settings_get_string (view->priv->editor_settings, XED_SETTINGS_EDITOR_FONT);
|
|
|
|
xed_view_set_font (view, FALSE, editor_font);
|
|
|
|
g_free (editor_font);
|
|
}
|
|
else
|
|
{
|
|
xed_view_set_font (view, TRUE, NULL);
|
|
}
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_DISPLAY_LINE_NUMBERS,
|
|
view,
|
|
"show-line-numbers",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_AUTO_INDENT,
|
|
view,
|
|
"auto-indent",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_TABS_SIZE,
|
|
view,
|
|
"tab-width",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_INSERT_SPACES,
|
|
view,
|
|
"insert-spaces-instead-of-tabs",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_DISPLAY_RIGHT_MARGIN,
|
|
view,
|
|
"show-right-margin",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_RIGHT_MARGIN_POSITION,
|
|
view,
|
|
"right-margin-position",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_HIGHLIGHT_CURRENT_LINE,
|
|
view,
|
|
"highlight-current-line",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_WRAP_MODE,
|
|
view,
|
|
"wrap-mode",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_settings_bind (priv->editor_settings,
|
|
XED_SETTINGS_SMART_HOME_END,
|
|
view,
|
|
"smart-home-end",
|
|
G_SETTINGS_BIND_GET);
|
|
|
|
g_object_set (G_OBJECT (view),
|
|
"indent_on_tab", TRUE,
|
|
NULL);
|
|
|
|
gutter = gtk_source_view_get_gutter (GTK_SOURCE_VIEW (view), GTK_TEXT_WINDOW_LEFT);
|
|
priv->renderer = g_object_new (XED_TYPE_VIEW_GUTTER_RENDERER,
|
|
"size", 2,
|
|
NULL);
|
|
g_object_ref (priv->renderer);
|
|
gtk_source_gutter_insert (gutter, priv->renderer, 0);
|
|
|
|
#if GTK_CHECK_VERSION (3, 18, 0)
|
|
gtk_text_view_set_top_margin (GTK_TEXT_VIEW (view), 2);
|
|
#endif
|
|
|
|
G_OBJECT_CLASS (xed_view_parent_class)->constructed (object);
|
|
}
|
|
|
|
static gint
|
|
xed_view_focus_out (GtkWidget *widget,
|
|
GdkEventFocus *event)
|
|
{
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
GTK_WIDGET_CLASS (xed_view_parent_class)->focus_out_event (widget, event);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static GdkAtom
|
|
drag_get_uri_target (GtkWidget *widget,
|
|
GdkDragContext *context)
|
|
{
|
|
GdkAtom target;
|
|
GtkTargetList *tl;
|
|
|
|
tl = gtk_target_list_new (NULL, 0);
|
|
gtk_target_list_add_uri_targets (tl, 0);
|
|
|
|
target = gtk_drag_dest_find_target (widget, context, tl);
|
|
gtk_target_list_unref (tl);
|
|
|
|
return target;
|
|
}
|
|
|
|
static gboolean
|
|
xed_view_drag_motion (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint timestamp)
|
|
{
|
|
gboolean result;
|
|
|
|
/* Chain up to allow textview to scroll and position dnd mark, note
|
|
* that this needs to be checked if gtksourceview or gtktextview
|
|
* changes drag_motion behaviour */
|
|
result = GTK_WIDGET_CLASS (xed_view_parent_class)->drag_motion (widget, context, x, y, timestamp);
|
|
|
|
/* If this is a URL, deal with it here */
|
|
if (drag_get_uri_target (widget, context) != GDK_NONE)
|
|
{
|
|
gdk_drag_status (context, gdk_drag_context_get_suggested_action (context), timestamp);
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void
|
|
xed_view_drag_data_received (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection_data,
|
|
guint info,
|
|
guint timestamp)
|
|
{
|
|
gchar **uri_list;
|
|
|
|
/* If this is an URL emit DROP_URIS, otherwise chain up the signal */
|
|
if (info == TARGET_URI_LIST)
|
|
{
|
|
uri_list = xed_utils_drop_get_uris (selection_data);
|
|
|
|
if (uri_list != NULL)
|
|
{
|
|
g_signal_emit (widget, view_signals[DROP_URIS], 0, uri_list);
|
|
g_strfreev (uri_list);
|
|
gtk_drag_finish (context, TRUE, FALSE, timestamp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GTK_WIDGET_CLASS (xed_view_parent_class)->drag_data_received (widget, context, x, y, selection_data, info,
|
|
timestamp);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
xed_view_drag_drop (GtkWidget *widget,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
guint timestamp)
|
|
{
|
|
gboolean result;
|
|
GdkAtom target;
|
|
|
|
/* If this is a URL, just get the drag data */
|
|
target = drag_get_uri_target (widget, context);
|
|
|
|
if (target != GDK_NONE)
|
|
{
|
|
gtk_drag_get_data (widget, context, target, timestamp);
|
|
result = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* Chain up */
|
|
result = GTK_WIDGET_CLASS (xed_view_parent_class)->drag_drop (widget, context, x, y, timestamp);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static GtkWidget *
|
|
create_line_numbers_menu (GtkWidget *view)
|
|
{
|
|
GtkWidget *menu;
|
|
GtkWidget *item;
|
|
|
|
menu = gtk_menu_new ();
|
|
|
|
item = gtk_check_menu_item_new_with_mnemonic (_("_Display line numbers"));
|
|
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(item),
|
|
gtk_source_view_get_show_line_numbers (GTK_SOURCE_VIEW(view)));
|
|
|
|
g_settings_bind (XED_VIEW (view)->priv->editor_settings,
|
|
"active",
|
|
item,
|
|
XED_SETTINGS_DISPLAY_LINE_NUMBERS,
|
|
G_SETTINGS_BIND_SET);
|
|
|
|
gtk_menu_shell_append (GTK_MENU_SHELL(menu), item);
|
|
|
|
gtk_widget_show_all (menu);
|
|
|
|
return menu;
|
|
}
|
|
|
|
static void
|
|
show_line_numbers_menu (GtkWidget *view,
|
|
GdkEventButton *event)
|
|
{
|
|
GtkWidget *menu;
|
|
|
|
menu = create_line_numbers_menu (view);
|
|
gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
|
|
}
|
|
|
|
static gboolean
|
|
xed_view_button_press_event (GtkWidget *widget,
|
|
GdkEventButton *event)
|
|
{
|
|
if ((event->type == GDK_BUTTON_PRESS) &&
|
|
(event->button == 3) &&
|
|
(event->window == gtk_text_view_get_window (GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_LEFT)))
|
|
{
|
|
show_line_numbers_menu (widget, event);
|
|
return TRUE;
|
|
}
|
|
|
|
return GTK_WIDGET_CLASS (xed_view_parent_class)->button_press_event (widget, event);
|
|
}
|
|
|
|
static void
|
|
xed_view_realize (GtkWidget *widget)
|
|
{
|
|
XedView *view = XED_VIEW (widget);
|
|
|
|
if (!view->priv->view_realized)
|
|
{
|
|
peas_extension_set_call (view->priv->extensions, "activate");
|
|
view->priv->view_realized = TRUE;
|
|
}
|
|
|
|
GTK_WIDGET_CLASS (xed_view_parent_class)->realize (widget);
|
|
}
|
|
|
|
static void
|
|
delete_line (GtkTextView *text_view,
|
|
gint count)
|
|
{
|
|
GtkTextIter start;
|
|
GtkTextIter end;
|
|
GtkTextBuffer *buffer;
|
|
|
|
buffer = gtk_text_view_get_buffer (text_view);
|
|
|
|
gtk_text_view_reset_im_context (text_view);
|
|
|
|
/* If there is a selection delete the selected lines and
|
|
* ignore count */
|
|
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
|
{
|
|
gtk_text_iter_order (&start, &end);
|
|
if (gtk_text_iter_starts_line (&end))
|
|
{
|
|
/* Do no delete the line with the cursor if the cursor
|
|
* is at the beginning of the line */
|
|
count = 0;
|
|
}
|
|
else
|
|
{
|
|
count = 1;
|
|
}
|
|
}
|
|
|
|
gtk_text_iter_set_line_offset (&start, 0);
|
|
|
|
if (count > 0)
|
|
{
|
|
gtk_text_iter_forward_lines (&end, count);
|
|
if (gtk_text_iter_is_end (&end))
|
|
{
|
|
if (gtk_text_iter_backward_line (&start) && !gtk_text_iter_ends_line (&start))
|
|
{
|
|
gtk_text_iter_forward_to_line_end (&start);
|
|
}
|
|
}
|
|
}
|
|
else if (count < 0)
|
|
{
|
|
if (!gtk_text_iter_ends_line (&end))
|
|
{
|
|
gtk_text_iter_forward_to_line_end (&end);
|
|
}
|
|
|
|
while (count < 0)
|
|
{
|
|
if (!gtk_text_iter_backward_line (&start))
|
|
{
|
|
break;
|
|
}
|
|
++count;
|
|
}
|
|
|
|
if (count == 0)
|
|
{
|
|
if (!gtk_text_iter_ends_line (&start))
|
|
{
|
|
gtk_text_iter_forward_to_line_end (&start);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gtk_text_iter_forward_line (&end);
|
|
}
|
|
}
|
|
|
|
if (!gtk_text_iter_equal (&start, &end))
|
|
{
|
|
GtkTextIter cur = start;
|
|
gtk_text_iter_set_line_offset (&cur, 0);
|
|
gtk_text_buffer_begin_user_action (buffer);
|
|
gtk_text_buffer_place_cursor (buffer, &cur);
|
|
gtk_text_buffer_delete_interactive (buffer, &start, &end, gtk_text_view_get_editable (text_view));
|
|
gtk_text_buffer_end_user_action (buffer);
|
|
gtk_text_view_scroll_mark_onscreen (text_view, gtk_text_buffer_get_insert (buffer));
|
|
}
|
|
else
|
|
{
|
|
gtk_widget_error_bell (GTK_WIDGET(text_view));
|
|
}
|
|
}
|
|
|
|
static void
|
|
xed_view_delete_from_cursor (GtkTextView *text_view,
|
|
GtkDeleteType type,
|
|
gint count)
|
|
{
|
|
/* We override the standard handler for delete_from_cursor since
|
|
the GTK_DELETE_PARAGRAPHS case is not implemented as we like (i.e. it
|
|
does not remove the carriage return in the previous line)
|
|
*/
|
|
switch (type)
|
|
{
|
|
case GTK_DELETE_PARAGRAPHS:
|
|
delete_line (text_view, count);
|
|
break;
|
|
default:
|
|
GTK_TEXT_VIEW_CLASS (xed_view_parent_class)->delete_from_cursor (text_view, type, count);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static GtkTextBuffer *
|
|
xed_view_create_buffer (GtkTextView *text_view)
|
|
{
|
|
return GTK_TEXT_BUFFER (xed_document_new ());
|
|
}
|
|
|
|
static void
|
|
xed_view_class_init (XedViewClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
GtkTextViewClass *text_view_class = GTK_TEXT_VIEW_CLASS (klass);
|
|
GtkBindingSet *binding_set;
|
|
|
|
object_class->dispose = xed_view_dispose;
|
|
object_class->constructed = xed_view_constructed;
|
|
|
|
widget_class->focus_out_event = xed_view_focus_out;
|
|
|
|
/*
|
|
* Override the gtk_text_view_drag_motion and drag_drop
|
|
* functions to get URIs
|
|
*
|
|
* If the mime type is text/uri-list, then we will accept
|
|
* the potential drop, or request the data (depending on the
|
|
* function).
|
|
*
|
|
* If the drag context has any other mime type, then pass the
|
|
* information onto the GtkTextView's standard handlers.
|
|
* (widget_class->function_name).
|
|
*
|
|
* See bug #89881 for details
|
|
*/
|
|
widget_class->drag_motion = xed_view_drag_motion;
|
|
widget_class->drag_data_received = xed_view_drag_data_received;
|
|
widget_class->drag_drop = xed_view_drag_drop;
|
|
widget_class->button_press_event = xed_view_button_press_event;
|
|
widget_class->realize = xed_view_realize;
|
|
|
|
text_view_class->delete_from_cursor = xed_view_delete_from_cursor;
|
|
text_view_class->create_buffer = xed_view_create_buffer;
|
|
|
|
/* A new signal DROP_URIS has been added to allow plugins to intercept
|
|
* the default dnd behaviour of 'text/uri-list'. XedView now handles
|
|
* dnd in the default handlers of drag_drop, drag_motion and
|
|
* drag_data_received. The view emits drop_uris from drag_data_received
|
|
* if valid uris have been dropped. Plugins should connect to
|
|
* drag_motion, drag_drop and drag_data_received to change this
|
|
* default behaviour. They should _NOT_ use this signal because this
|
|
* will not prevent xed from loading the uri
|
|
*/
|
|
view_signals[DROP_URIS] =
|
|
g_signal_new ("drop_uris",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
|
G_STRUCT_OFFSET (XedViewClass, drop_uris),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__BOXED,
|
|
G_TYPE_NONE, 1, G_TYPE_STRV);
|
|
|
|
g_type_class_add_private (klass, sizeof (XedViewPrivate));
|
|
|
|
binding_set = gtk_binding_set_by_class (klass);
|
|
|
|
gtk_binding_entry_add_signal (binding_set, GDK_KEY_d, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM,
|
|
GTK_DELETE_PARAGRAPHS, G_TYPE_INT, 1);
|
|
}
|
|
|
|
/**
|
|
* xed_view_new:
|
|
* @doc: a #XedDocument
|
|
*
|
|
* Creates a new #XedView object displaying the @doc document.
|
|
* @doc cannot be %NULL.
|
|
*
|
|
* Return value: a new #XedView
|
|
**/
|
|
GtkWidget *
|
|
xed_view_new (XedDocument *doc)
|
|
{
|
|
GtkWidget *view;
|
|
|
|
xed_debug_message (DEBUG_VIEW, "START");
|
|
|
|
g_return_val_if_fail(XED_IS_DOCUMENT (doc), NULL);
|
|
|
|
view = GTK_WIDGET(g_object_new (XED_TYPE_VIEW, "buffer", doc, NULL));
|
|
|
|
xed_debug_message (DEBUG_VIEW, "END: %d", G_OBJECT (view)->ref_count);
|
|
|
|
gtk_widget_show_all (view);
|
|
|
|
return view;
|
|
}
|
|
|
|
void
|
|
xed_view_cut_clipboard (XedView *view)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
GtkClipboard *clipboard;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET(view), GDK_SELECTION_CLIPBOARD);
|
|
|
|
/* FIXME: what is default editability of a buffer? */
|
|
gtk_text_buffer_cut_clipboard (buffer, clipboard, !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
|
|
|
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(view), gtk_text_buffer_get_insert (buffer), XED_VIEW_SCROLL_MARGIN,
|
|
FALSE, 0.0, 0.0);
|
|
}
|
|
|
|
void
|
|
xed_view_copy_clipboard (XedView *view)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
GtkClipboard *clipboard;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET(view), GDK_SELECTION_CLIPBOARD);
|
|
gtk_text_buffer_copy_clipboard (buffer, clipboard);
|
|
}
|
|
|
|
void
|
|
xed_view_paste_clipboard (XedView *view)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
GtkClipboard *clipboard;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
clipboard = gtk_widget_get_clipboard (GTK_WIDGET(view), GDK_SELECTION_CLIPBOARD);
|
|
|
|
/* FIXME: what is default editability of a buffer? */
|
|
gtk_text_buffer_paste_clipboard (buffer, clipboard, NULL, !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
|
|
|
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(view), gtk_text_buffer_get_insert (buffer), XED_VIEW_SCROLL_MARGIN,
|
|
FALSE, 0.0, 0.0);
|
|
}
|
|
|
|
/**
|
|
* xed_view_delete_selection:
|
|
* @view: a #XedView
|
|
*
|
|
* Deletes the text currently selected in the #GtkTextBuffer associated
|
|
* to the view and scroll to the cursor position.
|
|
**/
|
|
void
|
|
xed_view_delete_selection (XedView *view)
|
|
{
|
|
GtkTextBuffer *buffer = NULL;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
/* FIXME: what is default editability of a buffer? */
|
|
gtk_text_buffer_delete_selection (buffer, TRUE, !xed_document_get_readonly (XED_DOCUMENT(buffer)));
|
|
|
|
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(view), gtk_text_buffer_get_insert (buffer), XED_VIEW_SCROLL_MARGIN,
|
|
FALSE, 0.0, 0.0);
|
|
}
|
|
|
|
/**
|
|
* xed_view_select_all:
|
|
* @view: a #XedView
|
|
*
|
|
* Selects all the text displayed in the @view.
|
|
**/
|
|
void
|
|
xed_view_select_all (XedView *view)
|
|
{
|
|
GtkTextBuffer *buffer = NULL;
|
|
GtkTextIter start, end;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
gtk_text_buffer_get_bounds (buffer, &start, &end);
|
|
gtk_text_buffer_select_range (buffer, &start, &end);
|
|
}
|
|
|
|
/**
|
|
* xed_view_scroll_to_cursor:
|
|
* @view: a #XedView
|
|
*
|
|
* Scrolls the @view to the cursor position.
|
|
**/
|
|
void
|
|
xed_view_scroll_to_cursor (XedView *view)
|
|
{
|
|
GtkTextBuffer* buffer = NULL;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view));
|
|
g_return_if_fail(buffer != NULL);
|
|
|
|
gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW(view), gtk_text_buffer_get_insert (buffer), 0.25, FALSE, 0.0, 0.0);
|
|
}
|
|
|
|
/* FIXME this is an issue for introspection */
|
|
/**
|
|
* xed_view_set_font:
|
|
* @view: a #XedView
|
|
* @def: whether to reset the default font
|
|
* @font_name: the name of the font to use
|
|
*
|
|
* If @def is #TRUE, resets the font of the @view to the default font
|
|
* otherwise sets it to @font_name.
|
|
**/
|
|
void
|
|
xed_view_set_font (XedView *view,
|
|
gboolean def,
|
|
const gchar *font_name)
|
|
{
|
|
PangoFontDescription *font_desc = NULL;
|
|
|
|
xed_debug (DEBUG_VIEW);
|
|
|
|
g_return_if_fail(XED_IS_VIEW (view));
|
|
|
|
if (def)
|
|
{
|
|
GObject *settings;
|
|
gchar *font;
|
|
|
|
settings = _xed_app_get_settings (XED_APP (g_application_get_default ()));
|
|
font = xed_settings_get_system_font (XED_SETTINGS (settings));
|
|
font_desc = pango_font_description_from_string (font);
|
|
|
|
g_free (font);
|
|
}
|
|
else
|
|
{
|
|
g_return_if_fail (font_name != NULL);
|
|
font_desc = pango_font_description_from_string (font_name);
|
|
}
|
|
|
|
g_return_if_fail (font_desc != NULL);
|
|
gtk_widget_modify_font (GTK_WIDGET (view), font_desc);
|
|
pango_font_description_free (font_desc);
|
|
}
|