/* * gedit-quick-highlight-plugin.c * * Copyright (C) 2018 Martin Blanchard * * 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 2, 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 . * */ #include "config.h" #include #include #include #include #include #include "gedit-quick-highlight-plugin.h" struct _GeditQuickHighlightPluginPrivate { GeditView *view; GeditDocument *buffer; GtkTextMark *insert_mark; GtkSourceSearchContext *search_context; GtkSourceStyle *style; gulong buffer_handler_id; gulong mark_set_handler_id; gulong delete_range_handler_id; gulong style_scheme_handler_id; guint queued_highlight; }; enum { PROP_0, PROP_VIEW }; static void gedit_view_activatable_iface_init (GeditViewActivatableInterface *iface); G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditQuickHighlightPlugin, gedit_quick_highlight_plugin, PEAS_TYPE_EXTENSION_BASE, 0, G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_VIEW_ACTIVATABLE, gedit_view_activatable_iface_init) G_ADD_PRIVATE_DYNAMIC (GeditQuickHighlightPlugin)) static void gedit_quick_highlight_plugin_notify_buffer_cb (GObject *object, GParamSpec *pspec, gpointer user_data); static void gedit_quick_highlight_plugin_mark_set_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, GtkTextMark *mark, gpointer user_data); static void gedit_quick_highlight_plugin_delete_range_cb (GtkTextBuffer *textbuffer, GtkTextIter *start, GtkTextIter *end, gpointer user_data); static void gedit_quick_highlight_plugin_notify_style_scheme_cb (GObject *object, GParamSpec *pspec, gpointer user_data); static void gedit_quick_highlight_plugin_load_style (GeditQuickHighlightPlugin *plugin) { GtkSourceStyleScheme *style_scheme; GtkSourceStyle *style = NULL; g_return_if_fail (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); if (plugin->priv->buffer == NULL) { return; } gedit_debug (DEBUG_PLUGINS); g_clear_object (&plugin->priv->style); style_scheme = gtk_source_buffer_get_style_scheme (GTK_SOURCE_BUFFER (plugin->priv->buffer)); if (style_scheme != NULL) { style = gtk_source_style_scheme_get_style (style_scheme, "quick-highlight-match"); if (style != NULL) { plugin->priv->style = gtk_source_style_copy (style); } } } static gboolean gedit_quick_highlight_plugin_highlight_worker (gpointer user_data) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (user_data); GtkSourceSearchSettings *search_settings; GtkTextIter start, end; g_autofree gchar *text = NULL; g_assert (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); plugin->priv->queued_highlight = 0; if (!gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (plugin->priv->buffer), &start, &end)) { g_clear_object (&plugin->priv->search_context); return G_SOURCE_REMOVE; } if (gtk_text_iter_get_line (&start) != gtk_text_iter_get_line (&end)) { g_clear_object (&plugin->priv->search_context); return G_SOURCE_REMOVE; } if (plugin->priv->search_context == NULL) { search_settings = g_object_new (GTK_SOURCE_TYPE_SEARCH_SETTINGS, "at-word-boundaries", FALSE, "case-sensitive", TRUE, "regex-enabled", FALSE, NULL); plugin->priv->search_context = g_object_new (GTK_SOURCE_TYPE_SEARCH_CONTEXT, "buffer", plugin->priv->buffer, "highlight", FALSE, "match-style", plugin->priv->style, "settings", search_settings, NULL); g_object_unref (search_settings); } else { search_settings = gtk_source_search_context_get_settings (plugin->priv->search_context); } text = gtk_text_iter_get_slice (&start, &end); gtk_source_search_settings_set_search_text (search_settings, text); gtk_source_search_context_set_highlight (plugin->priv->search_context, TRUE); return G_SOURCE_REMOVE; } static void gedit_quick_highlight_plugin_queue_update (GeditQuickHighlightPlugin *plugin) { g_return_if_fail (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); if (plugin->priv->queued_highlight != 0) { return; } plugin->priv->queued_highlight = gdk_threads_add_idle_full (G_PRIORITY_LOW, gedit_quick_highlight_plugin_highlight_worker, g_object_ref (plugin), g_object_unref); } static void gedit_quick_highlight_plugin_notify_weak_buffer_cb (gpointer data, GObject *where_the_object_was) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (data); g_assert (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); plugin->priv->style_scheme_handler_id = 0; plugin->priv->buffer = NULL; } static void gedit_quick_highlight_plugin_unref_weak_buffer (GeditQuickHighlightPlugin *plugin) { g_return_if_fail (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); if (plugin->priv->buffer == NULL) { return; } if (plugin->priv->delete_range_handler_id > 0) { g_signal_handler_disconnect (plugin->priv->buffer, plugin->priv->delete_range_handler_id); plugin->priv->delete_range_handler_id = 0; } if (plugin->priv->mark_set_handler_id > 0) { g_signal_handler_disconnect (plugin->priv->buffer, plugin->priv->mark_set_handler_id); plugin->priv->mark_set_handler_id = 0; } if (plugin->priv->style_scheme_handler_id > 0) { g_signal_handler_disconnect (plugin->priv->buffer, plugin->priv->style_scheme_handler_id); plugin->priv->style_scheme_handler_id = 0; } g_object_weak_unref (G_OBJECT (plugin->priv->buffer), gedit_quick_highlight_plugin_notify_weak_buffer_cb, plugin); plugin->priv->buffer = NULL; } static void gedit_quick_highlight_plugin_set_buffer (GeditQuickHighlightPlugin *plugin, GeditDocument *buffer) { g_return_if_fail (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); g_return_if_fail (GEDIT_IS_DOCUMENT (buffer)); if (plugin->priv->buffer == buffer) { return; } gedit_debug (DEBUG_PLUGINS); gedit_quick_highlight_plugin_unref_weak_buffer (plugin); plugin->priv->buffer = buffer; if (plugin->priv->buffer != NULL) { g_object_weak_ref (G_OBJECT (plugin->priv->buffer), gedit_quick_highlight_plugin_notify_weak_buffer_cb, plugin); plugin->priv->style_scheme_handler_id = g_signal_connect (plugin->priv->buffer, "notify::style-scheme", G_CALLBACK (gedit_quick_highlight_plugin_notify_style_scheme_cb), plugin); plugin->priv->mark_set_handler_id = g_signal_connect (plugin->priv->buffer, "mark-set", G_CALLBACK (gedit_quick_highlight_plugin_mark_set_cb), plugin); plugin->priv->delete_range_handler_id = g_signal_connect (plugin->priv->buffer, "delete-range", G_CALLBACK (gedit_quick_highlight_plugin_delete_range_cb), plugin); plugin->priv->insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (plugin->priv->buffer)); gedit_quick_highlight_plugin_load_style (plugin); gedit_quick_highlight_plugin_queue_update (plugin); } } static void gedit_quick_highlight_plugin_mark_set_cb (GtkTextBuffer *textbuffer, GtkTextIter *location, GtkTextMark *mark, gpointer user_data) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (user_data); g_assert (GEDIT_QUICK_HIGHLIGHT_PLUGIN (plugin)); if G_LIKELY (mark != plugin->priv->insert_mark) { return; } gedit_quick_highlight_plugin_queue_update (plugin); } static void gedit_quick_highlight_plugin_delete_range_cb (GtkTextBuffer *textbuffer, GtkTextIter *start, GtkTextIter *end, gpointer user_data) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (user_data); g_assert (GEDIT_QUICK_HIGHLIGHT_PLUGIN (plugin)); gedit_quick_highlight_plugin_queue_update (plugin); } static void gedit_quick_highlight_plugin_notify_style_scheme_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (user_data); g_assert (GEDIT_QUICK_HIGHLIGHT_PLUGIN (plugin)); gedit_quick_highlight_plugin_load_style (plugin); } static void gedit_quick_highlight_plugin_dispose (GObject *object) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (object); g_clear_object (&plugin->priv->search_context); gedit_quick_highlight_plugin_unref_weak_buffer (plugin); g_clear_object (&plugin->priv->view); G_OBJECT_CLASS (gedit_quick_highlight_plugin_parent_class)->dispose (object); } static void gedit_quick_highlight_plugin_finalize (GObject *object) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (object); g_clear_object (&plugin->priv->style); G_OBJECT_CLASS (gedit_quick_highlight_plugin_parent_class)->finalize (object); } static void gedit_quick_highlight_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (object); switch (prop_id) { case PROP_VIEW: g_value_set_object (value, plugin->priv->view); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gedit_quick_highlight_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (object); switch (prop_id) { case PROP_VIEW: plugin->priv->view = GEDIT_VIEW (g_value_dup_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gedit_quick_highlight_plugin_class_init (GeditQuickHighlightPluginClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = gedit_quick_highlight_plugin_dispose; object_class->finalize = gedit_quick_highlight_plugin_finalize; object_class->set_property = gedit_quick_highlight_plugin_set_property; object_class->get_property = gedit_quick_highlight_plugin_get_property; g_object_class_override_property (object_class, PROP_VIEW, "view"); } static void gedit_quick_highlight_plugin_class_finalize (GeditQuickHighlightPluginClass *klass) { } static void gedit_quick_highlight_plugin_init (GeditQuickHighlightPlugin *plugin) { plugin->priv = gedit_quick_highlight_plugin_get_instance_private (plugin); } static void gedit_quick_highlight_plugin_activate (GeditViewActivatable *activatable) { GeditQuickHighlightPlugin *plugin; GtkTextBuffer *buffer; gedit_debug (DEBUG_PLUGINS); plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (activatable); plugin->priv->buffer_handler_id = g_signal_connect (plugin->priv->view, "notify::buffer", G_CALLBACK (gedit_quick_highlight_plugin_notify_buffer_cb), plugin); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (plugin->priv->view)); gedit_quick_highlight_plugin_set_buffer (plugin, GEDIT_DOCUMENT (buffer)); } static void gedit_quick_highlight_plugin_deactivate (GeditViewActivatable *activatable) { GeditQuickHighlightPlugin *plugin; gedit_debug (DEBUG_PLUGINS); plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (activatable); g_clear_object (&plugin->priv->style); g_clear_object (&plugin->priv->search_context); gedit_quick_highlight_plugin_unref_weak_buffer (plugin); if (plugin->priv->view != NULL && plugin->priv->buffer_handler_id > 0) { g_signal_handler_disconnect (plugin->priv->view, plugin->priv->buffer_handler_id); plugin->priv->buffer_handler_id = 0; } } static void gedit_quick_highlight_plugin_notify_buffer_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { GeditQuickHighlightPlugin *plugin = GEDIT_QUICK_HIGHLIGHT_PLUGIN (user_data); GtkTextBuffer *buffer; g_assert (GEDIT_IS_QUICK_HIGHLIGHT_PLUGIN (plugin)); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (plugin->priv->view)); gedit_quick_highlight_plugin_set_buffer (plugin, GEDIT_DOCUMENT (buffer)); } static void gedit_view_activatable_iface_init (GeditViewActivatableInterface *iface) { iface->activate = gedit_quick_highlight_plugin_activate; iface->deactivate = gedit_quick_highlight_plugin_deactivate; } G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module) { gedit_quick_highlight_plugin_register_type (G_TYPE_MODULE (module)); peas_object_module_register_extension_type (module, GEDIT_TYPE_VIEW_ACTIVATABLE, GEDIT_TYPE_QUICK_HIGHLIGHT_PLUGIN); } /* ex:set ts=8 noet: */