From c0c513f3ef7e7ea432e799d8a5e10cfe94d38908 Mon Sep 17 00:00:00 2001 From: mbkma Date: Wed, 10 Feb 2021 12:02:25 +0100 Subject: Introduce PlumaWindowActivatable, PlumaAppActivatable, PlumaViewActivatable These interfaces are for extensions that should be activated against a window/app/view. Backport from - https://gitlab.gnome.org/GNOME/gedit/-/commit/4fe7161560941ae1aa42165ff4d71121ad6f67b9 - https://gitlab.gnome.org/GNOME/gedit/-/commit/56a790a6851ebc98766cc4aca27cb32dde1b41bf - https://gitlab.gnome.org/GNOME/gedit/-/commit/210ed41e48988646203fc94eba19ce94657821cd In pluma-app.c we use gtk_main_quit instead of app object unref when last window closed. Plugin engine finalization calls app_get_default which reconstructs the app object. Before that was reasonably ok because it didn't really do anything, but now the app does stuff in 'init'. See https://gitlab.gnome.org/GNOME/gedit/-/commit/90c9889a4a31fbebfa042c5d2c64bb2b05160b10 --- pluma/Makefile.am | 23 ++++---- pluma/pluma-app-activatable.c | 105 ++++++++++++++++++++++++++++++++++++ pluma/pluma-app-activatable.h | 60 +++++++++++++++++++++ pluma/pluma-app.c | 53 ++++++++++++++---- pluma/pluma-view-activatable.c | 93 ++++++++++++++++++++++++++++++++ pluma/pluma-view-activatable.h | 59 ++++++++++++++++++++ pluma/pluma-view.c | 101 ++++++++++++++++++++++++++++++++++ pluma/pluma-window-activatable.c | 114 +++++++++++++++++++++++++++++++++++++++ pluma/pluma-window-activatable.h | 61 +++++++++++++++++++++ pluma/pluma-window.c | 29 +++++----- 10 files changed, 666 insertions(+), 32 deletions(-) create mode 100644 pluma/pluma-app-activatable.c create mode 100644 pluma/pluma-app-activatable.h create mode 100644 pluma/pluma-view-activatable.c create mode 100644 pluma/pluma-view-activatable.h create mode 100644 pluma/pluma-window-activatable.c create mode 100644 pluma/pluma-window-activatable.h diff --git a/pluma/Makefile.am b/pluma/Makefile.am index 1dc9403c..28c869f0 100644 --- a/pluma/Makefile.am +++ b/pluma/Makefile.am @@ -8,7 +8,7 @@ noinst_LTLIBRARIES = libpluma.la AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(srcdir) \ - -I$(srcdir)/mate-submodules/libegg \ + -I$(srcdir)/mate-submodules/libegg \ $(PLUMA_CFLAGS) \ $(WARN_CFLAGS) \ $(INTROSPECTION_CFLAGS) \ @@ -65,6 +65,7 @@ NOINST_H_FILES = \ INST_H_FILES = \ pluma-app.h \ + pluma-app-activatable.h \ pluma-commands.h \ pluma-debug.h \ pluma-document.h \ @@ -82,7 +83,9 @@ INST_H_FILES = \ pluma-tab.h \ pluma-utils.h \ pluma-view.h \ - pluma-window.h + pluma-view-activatable.h \ + pluma-window.h \ + pluma-window-activatable.h if !ENABLE_GVFS_METADATA INST_H_FILES += pluma-metadata-manager.h @@ -95,6 +98,7 @@ header_DATA = \ libpluma_c_files = \ pluma-app.c \ + pluma-app-activatable.c \ pluma-close-button.c \ pluma-commands-documents.c \ pluma-commands-edit.c \ @@ -138,12 +142,16 @@ libpluma_c_files = \ pluma-tab-label.c \ pluma-utils.c \ pluma-view.c \ + pluma-view-activatable.c \ pluma-window.c \ + pluma-window-activatable.c \ plumatextregion.c +nodist_libpluma_la_SOURCES = \ + $(BUILT_SOURCES) + libpluma_la_SOURCES = \ $(libpluma_c_files) \ - $(BUILT_SOURCES) \ $(BACON_FILES) \ $(POSIXIO_FILES) \ $(NOINST_H_FILES) \ @@ -187,11 +195,11 @@ INTROSPECTION_GIRS = Pluma-1.0.gir INTROSPECTION_SCANNER_ARGS = -I$(top_srcdir) --warn-all Pluma-1.0.gir: pluma -Pluma_1_0_gir_INCLUDES = Gtk-3.0 GtkSource-3.0 -Pluma_1_0_gir_FILES = $(INST_H_FILES) $(libpluma_c_files) $(BUILT_SOURCES) +Pluma_1_0_gir_NAMESPACE = Pluma Pluma_1_0_gir_VERSION = 1.0 Pluma_1_0_gir_PROGRAM = $(builddir)/pluma -Pluma_1_0_gir_NAMESPACE = Pluma +Pluma_1_0_gir_FILES = $(INST_H_FILES) $(libpluma_c_files) $(BUILT_SOURCES) +Pluma_1_0_gir_INCLUDES = Gtk-3.0 GtkSource-3.0 girdir = $(datadir)/gir-1.0 gir_DATA = $(INTROSPECTION_GIRS) @@ -202,9 +210,6 @@ typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) CLEANFILES += $(gir_DATA) $(typelib_DATA) endif -dist-hook: - cd $(distdir); rm -f $(BUILT_SOURCES) - BACON_DIR=$(srcdir)/../../libbacon/src/ BACON_FILES=bacon-message-connection.h bacon-message-connection.c diff --git a/pluma/pluma-app-activatable.c b/pluma/pluma-app-activatable.c new file mode 100644 index 00000000..3d68d9fe --- /dev/null +++ b/pluma/pluma-app-activatable.c @@ -0,0 +1,105 @@ +/* + * pluma-app-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 Steve Frécinaux + * Copyright (C) 2010 Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#include + +#include "pluma-app-activatable.h" +#include "pluma-app.h" + +/** + * SECTION:pluma-app-activatable + * @short_description: Interface for activatable extensions on apps + * @see_also: #PeasExtensionSet + * + * #PlumaAppActivatable is an interface which should be implemented by + * extensions that should be activated on a pluma application. + **/ + +G_DEFINE_INTERFACE(PlumaAppActivatable, pluma_app_activatable, G_TYPE_OBJECT) + +void +pluma_app_activatable_default_init (PlumaAppActivatableInterface *iface) +{ + static gboolean initialized = FALSE; + + if (!initialized) + { + /** + * PlumaAppActivatable:app: + * + * The app property contains the pluma app for this + * #PlumaAppActivatable instance. + */ + g_object_interface_install_property (iface, + g_param_spec_object ("app", + "App", + "The pluma app", + PLUMA_TYPE_APP, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + initialized = TRUE; + } +} + +/** + * pluma_app_activatable_activate: + * @activatable: A #PlumaAppActivatable. + * + * Activates the extension on the application. + */ +void +pluma_app_activatable_activate (PlumaAppActivatable *activatable) +{ + PlumaAppActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_APP_ACTIVATABLE (activatable)); + + iface = PLUMA_APP_ACTIVATABLE_GET_IFACE (activatable); + + if (iface->activate != NULL) + { + iface->activate (activatable); + } +} + +/** + * pluma_app_activatable_deactivate: + * @activatable: A #PlumaAppActivatable. + * + * Deactivates the extension from the application. + * + */ +void +pluma_app_activatable_deactivate (PlumaAppActivatable *activatable) +{ + PlumaAppActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_APP_ACTIVATABLE (activatable)); + + iface = PLUMA_APP_ACTIVATABLE_GET_IFACE (activatable); + + if (iface->deactivate != NULL) + { + iface->deactivate (activatable); + } +} diff --git a/pluma/pluma-app-activatable.h b/pluma/pluma-app-activatable.h new file mode 100644 index 00000000..0362f546 --- /dev/null +++ b/pluma/pluma-app-activatable.h @@ -0,0 +1,60 @@ +/* + * pluma-app-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 - Steve Frécinaux + * Copyright (C) 2010 - Jesse van den Kieboom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#ifndef __PLUMA_APP_ACTIVATABLE_H__ +#define __PLUMA_APP_ACTIVATABLE_H__ + +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_APP_ACTIVATABLE (pluma_app_activatable_get_type ()) +#define PLUMA_APP_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_APP_ACTIVATABLE, PlumaAppActivatable)) +#define PLUMA_APP_ACTIVATABLE_IFACE(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), PLUMA_TYPE_APP_ACTIVATABLE, PlumaAppActivatableInterface)) +#define PLUMA_IS_APP_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_APP_ACTIVATABLE)) +#define PLUMA_APP_ACTIVATABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PLUMA_TYPE_APP_ACTIVATABLE, PlumaAppActivatableInterface)) + +typedef struct _PlumaAppActivatable PlumaAppActivatable; /* dummy typedef */ +typedef struct _PlumaAppActivatableInterface PlumaAppActivatableInterface; + +struct _PlumaAppActivatableInterface +{ + GTypeInterface g_iface; + + /* Virtual public methods */ + void (*activate) (PlumaAppActivatable *activatable); + void (*deactivate) (PlumaAppActivatable *activatable); +}; + +/* + * Public methods + */ +GType pluma_app_activatable_get_type (void) G_GNUC_CONST; + +void pluma_app_activatable_activate (PlumaAppActivatable *activatable); +void pluma_app_activatable_deactivate (PlumaAppActivatable *activatable); + +G_END_DECLS + +#endif /* __PLUMA_APP_ACTIVATABLE_H__ */ diff --git a/pluma/pluma-app.c b/pluma/pluma-app.c index 60ce9bac..ef4e3fe4 100644 --- a/pluma/pluma-app.c +++ b/pluma/pluma-app.c @@ -36,8 +36,10 @@ #include #include +#include #include #include + #include "pluma-app.h" #include "pluma-commands.h" #include "pluma-notebook.h" @@ -46,6 +48,8 @@ #include "pluma-enum-types.h" #include "pluma-dirs.h" #include "pluma-settings.h" +#include "pluma-app-activatable.h" +#include "pluma-plugins-engine.h" #define PLUMA_PAGE_SETUP_FILE "pluma-page-setup" #define PLUMA_PRINT_SETTINGS_FILE "pluma-print-settings" @@ -68,6 +72,8 @@ struct _PlumaAppPrivate GtkPrintSettings *print_settings; GSettings *window_settings; + + PeasExtensionSet *extensions; }; G_DEFINE_TYPE_WITH_PRIVATE (PlumaApp, pluma_app, G_TYPE_OBJECT) @@ -93,6 +99,7 @@ pluma_app_dispose (GObject *object) PlumaApp *app = PLUMA_APP (object); g_clear_object (&app->priv->window_settings); + g_clear_object (&app->priv->extensions); G_OBJECT_CLASS (pluma_app_parent_class)->dispose (object); } @@ -337,6 +344,25 @@ save_print_settings (PlumaApp *app) g_free (filename); } +static void +extension_added (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + PlumaApp *app) +{ + peas_extension_call (exten, "activate"); +} + +static void +extension_removed (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + PlumaApp *app) +{ + peas_extension_call (exten, "deactivate"); +} + + static void pluma_app_init (PlumaApp *app) { @@ -352,13 +378,23 @@ pluma_app_init (PlumaApp *app) /* initial lockdown state */ app->priv->lockdown = pluma_settings_get_lockdown (settings); -} -static void -app_weak_notify (gpointer data, - GObject *where_the_app_was) -{ - gtk_main_quit (); + app->priv->extensions = peas_extension_set_new (PEAS_ENGINE (pluma_plugins_engine_get_default ()), + PLUMA_TYPE_APP_ACTIVATABLE, + "app", app, + NULL); + + g_signal_connect (app->priv->extensions, + "extension-added", + G_CALLBACK (extension_added), + app); + + g_signal_connect (app->priv->extensions, + "extension-removed", + G_CALLBACK (extension_removed), + app); + + peas_extension_set_call (app->priv->extensions, "activate"); } /** @@ -381,9 +417,6 @@ pluma_app_get_default (void) g_object_add_weak_pointer (G_OBJECT (app), (gpointer) &app); - g_object_weak_ref (G_OBJECT (app), - app_weak_notify, - NULL); return app; } @@ -460,7 +493,7 @@ window_destroy (PlumaWindow *window, save_page_setup (app); save_print_settings (app); - g_object_unref (app); + gtk_main_quit (); } } diff --git a/pluma/pluma-view-activatable.c b/pluma/pluma-view-activatable.c new file mode 100644 index 00000000..ad29dee8 --- /dev/null +++ b/pluma/pluma-view-activatable.c @@ -0,0 +1,93 @@ +/* + * pluma-view-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#include + +#include "pluma-view-activatable.h" +#include "pluma-view.h" + +/** + * SECTION:pluma-view-activatable + * @short_description: Interface for activatable extensions on views + * @see_also: #PeasExtensionSet + * + * #PlumaViewActivatable is an interface which should be implemented by + * extensions that should be activated on a pluma view. + **/ +G_DEFINE_INTERFACE(PlumaViewActivatable, pluma_view_activatable, G_TYPE_OBJECT) + +void +pluma_view_activatable_default_init (PlumaViewActivatableInterface *iface) +{ + /** + * PlumaViewActivatable:view: + * + * The window property contains the pluma window for this + * #PlumaViewActivatable instance. + */ + g_object_interface_install_property (iface, + g_param_spec_object ("view", + "view", + "A pluma view", + PLUMA_TYPE_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * pluma_view_activatable_activate: + * @activatable: A #PlumaViewActivatable. + * + * Activates the extension on the window property. + */ +void +pluma_view_activatable_activate (PlumaViewActivatable *activatable) +{ + PlumaViewActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_VIEW_ACTIVATABLE (activatable)); + + iface = PLUMA_VIEW_ACTIVATABLE_GET_IFACE (activatable); + if (iface->activate != NULL) + { + iface->activate (activatable); + } +} + +/** + * pluma_view_activatable_deactivate: + * @activatable: A #PlumaViewActivatable. + * + * Deactivates the extension on the window property. + */ +void +pluma_view_activatable_deactivate (PlumaViewActivatable *activatable) +{ + PlumaViewActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_VIEW_ACTIVATABLE (activatable)); + + iface = PLUMA_VIEW_ACTIVATABLE_GET_IFACE (activatable); + if (iface->deactivate != NULL) + { + iface->deactivate (activatable); + } +} diff --git a/pluma/pluma-view-activatable.h b/pluma/pluma-view-activatable.h new file mode 100644 index 00000000..4fc170c8 --- /dev/null +++ b/pluma/pluma-view-activatable.h @@ -0,0 +1,59 @@ +/* + * pluma-view-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 - Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#ifndef __PLUMA_VIEW_ACTIVATABLE_H__ +#define __PLUMA_VIEW_ACTIVATABLE_H__ + +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_VIEW_ACTIVATABLE (pluma_view_activatable_get_type ()) +#define PLUMA_VIEW_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_VIEW_ACTIVATABLE, PlumaViewActivatable)) +#define PLUMA_VIEW_ACTIVATABLE_IFACE(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), PLUMA_TYPE_VIEW_ACTIVATABLE, PlumaViewActivatableInterface)) +#define PLUMA_IS_VIEW_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_VIEW_ACTIVATABLE)) +#define PLUMA_VIEW_ACTIVATABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PLUMA_TYPE_VIEW_ACTIVATABLE, PlumaViewActivatableInterface)) + +typedef struct _PlumaViewActivatable PlumaViewActivatable; /* dummy typedef */ +typedef struct _PlumaViewActivatableInterface PlumaViewActivatableInterface; + +struct _PlumaViewActivatableInterface +{ + GTypeInterface g_iface; + + /* Virtual public methods */ + void (*activate) (PlumaViewActivatable *activatable); + void (*deactivate) (PlumaViewActivatable *activatable); +}; + +/* + * Public methods + */ +GType pluma_view_activatable_get_type (void) G_GNUC_CONST; + +void pluma_view_activatable_activate (PlumaViewActivatable *activatable); +void pluma_view_activatable_deactivate (PlumaViewActivatable *activatable); + +G_END_DECLS + +#endif /* __PLUMA_VIEW_ACTIVATABLE_H__ */ diff --git a/pluma/pluma-view.c b/pluma/pluma-view.c index dfeb9154..d09599a7 100644 --- a/pluma/pluma-view.c +++ b/pluma/pluma-view.c @@ -39,10 +39,13 @@ #include #include +#include #include #include "pluma-view.h" +#include "pluma-view-activatable.h" +#include "pluma-plugins-engine.h" #include "pluma-debug.h" #include "pluma-pango.h" #include "pluma-utils.h" @@ -101,22 +104,29 @@ struct _PlumaViewPrivate GtkCssProvider *css_provider; PangoFontDescription *font_desc; + + PeasExtensionSet *extensions; }; /* The search entry completion is shared among all the views */ GtkListStore *search_completion_model = NULL; static void pluma_view_dispose (GObject *object); + static void pluma_view_finalize (GObject *object); + static gint pluma_view_focus_out (GtkWidget *widget, GdkEventFocus *event); + static gboolean pluma_view_scroll_event (GtkWidget *widget, GdkEventScroll *event); + static gboolean pluma_view_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint timestamp); + static void pluma_view_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, @@ -124,21 +134,30 @@ static void pluma_view_drag_data_received (GtkWidget *widget, GtkSelectionData *selection_data, guint info, guint timestamp); + static gboolean pluma_view_drag_drop (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint timestamp); +static void pluma_view_realize (GtkWidget *widget); + +static void pluma_view_unrealize (GtkWidget *widget); + static gboolean pluma_view_button_press_event (GtkWidget *widget, GdkEventButton *event); + static gboolean pluma_view_button_release_event (GtkWidget *widget, GdkEventButton *event); + static void pluma_view_populate_popup (GtkTextView *text_view, GtkWidget *widget); static gboolean start_interactive_search (PlumaView *view); + static gboolean start_interactive_goto_line (PlumaView *view); + static gboolean reset_searched_text (PlumaView *view); static void hide_search_window (PlumaView *view, @@ -146,6 +165,7 @@ static void hide_search_window (PlumaView *view, static gboolean pluma_view_draw (GtkWidget *widget, cairo_t *cr); + static void search_highlight_updated_cb (PlumaDocument *doc, GtkTextIter *start, GtkTextIter *end, @@ -251,6 +271,10 @@ pluma_view_class_init (PlumaViewClass *klass) widget_class->drag_drop = pluma_view_drag_drop; widget_class->button_press_event = pluma_view_button_press_event; widget_class->button_release_event = pluma_view_button_release_event; + + widget_class->realize = pluma_view_realize; + widget_class->unrealize = pluma_view_unrealize; + text_view_class->populate_popup = pluma_view_populate_popup; klass->start_interactive_search = start_interactive_search; klass->start_interactive_goto_line = start_interactive_goto_line; @@ -388,6 +412,11 @@ on_notify_buffer_cb (PlumaView *view, "search_highlight_updated", G_CALLBACK (search_highlight_updated_cb), view); + + /* We only activate the extensions when the right buffer is set, + * because most plugins will expect this behaviour, and we won't + * change the buffer later anyway. */ + peas_extension_set_call (view->priv->extensions, "activate", view); } #ifdef GTK_SOURCE_VERSION_3_24 @@ -578,6 +607,12 @@ pluma_view_init (PlumaView *view) if (tl != NULL) gtk_target_list_add_uri_targets (tl, TARGET_URI_LIST); + view->priv->extensions = + peas_extension_set_new (PEAS_ENGINE (pluma_plugins_engine_get_default ()), + PLUMA_TYPE_VIEW_ACTIVATABLE, + "view", view, + NULL); + /* Act on buffer change */ g_signal_connect (view, "notify::buffer", @@ -592,6 +627,12 @@ pluma_view_dispose (GObject *object) view = PLUMA_VIEW (object); + if (view->priv->extensions != NULL) + { + g_object_unref (view->priv->extensions); + view->priv->extensions = NULL; + } + if (view->priv->search_window != NULL) { gtk_widget_destroy (view->priv->search_window); @@ -1280,6 +1321,66 @@ search_window_button_press_event (GtkWidget *widget, return FALSE; } +static void +extension_added (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + PlumaView *view) +{ + pluma_view_activatable_activate (PLUMA_VIEW_ACTIVATABLE (exten)); +} + +static void +extension_removed (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + PlumaView *view) +{ + pluma_view_activatable_deactivate (PLUMA_VIEW_ACTIVATABLE (exten)); +} + +static void +pluma_view_realize (GtkWidget *widget) +{ + PlumaView *view = PLUMA_VIEW (widget); + + GTK_WIDGET_CLASS (pluma_view_parent_class)->realize (widget); + + 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); + + /* We only activate the extensions when the view is realized, + * because most plugins will expect this behaviour, and we won't + * change the buffer later anyway. */ + peas_extension_set_foreach (view->priv->extensions, + (PeasExtensionSetForeachFunc) extension_added, + view); +} + +static void +pluma_view_unrealize (GtkWidget *widget) +{ + PlumaView *view = PLUMA_VIEW (widget); + + g_signal_handlers_disconnect_by_func (view->priv->extensions, extension_added, view); + g_signal_handlers_disconnect_by_func (view->priv->extensions, extension_removed, view); + + /* We need to deactivate the extension on unrealize because it is not + mandatory that a view has been realized when we dispose it, leading + to deactivating the plugin without being activated */ + peas_extension_set_foreach (view->priv->extensions, + (PeasExtensionSetForeachFunc) extension_removed, + view); + + GTK_WIDGET_CLASS (pluma_view_parent_class)->unrealize (widget); +} + static void search_again (PlumaView *view, gboolean search_backward) diff --git a/pluma/pluma-window-activatable.c b/pluma/pluma-window-activatable.c new file mode 100644 index 00000000..74597b2a --- /dev/null +++ b/pluma/pluma-window-activatable.c @@ -0,0 +1,114 @@ +/* + * pluma-window-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#include + +#include "pluma-window-activatable.h" +#include "pluma-window.h" + +/** + * SECTION:pluma-window-activatable + * @short_description: Interface for activatable extensions on windows + * @see_also: #PeasExtensionSet + * + * #PlumaWindowActivatable is an interface which should be implemented by + * extensions that should be activated on a pluma main window. + **/ +G_DEFINE_INTERFACE(PlumaWindowActivatable, pluma_window_activatable, G_TYPE_OBJECT) + +void +pluma_window_activatable_default_init (PlumaWindowActivatableInterface *iface) +{ + /** + * PlumaWindowActivatable:window: + * + * The window property contains the pluma window for this + * #PlumaWindowActivatable instance. + */ + g_object_interface_install_property (iface, + g_param_spec_object ("window", + "Window", + "The pluma window", + PLUMA_TYPE_WINDOW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +/** + * pluma_window_activatable_activate: + * @activatable: A #PlumaWindowActivatable. + * + * Activates the extension on the window property. + */ +void +pluma_window_activatable_activate (PlumaWindowActivatable *activatable) +{ + PlumaWindowActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_WINDOW_ACTIVATABLE (activatable)); + + iface = PLUMA_WINDOW_ACTIVATABLE_GET_IFACE (activatable); + if (iface->activate != NULL) + { + iface->activate (activatable); + } +} + +/** + * pluma_window_activatable_deactivate: + * @activatable: A #PlumaWindowActivatable. + * + * Deactivates the extension on the window property. + */ +void +pluma_window_activatable_deactivate (PlumaWindowActivatable *activatable) +{ + PlumaWindowActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_WINDOW_ACTIVATABLE (activatable)); + + iface = PLUMA_WINDOW_ACTIVATABLE_GET_IFACE (activatable); + if (iface->deactivate != NULL) + { + iface->deactivate (activatable); + } +} + +/** + * pluma_window_activatable_update_state: + * @activatable: A #PlumaWindowActivatable. + * + * Triggers an update of the extension insternal state to take into account + * state changes in the window state, due to some event or user action. + */ +void +pluma_window_activatable_update_state (PlumaWindowActivatable *activatable) +{ + PlumaWindowActivatableInterface *iface; + + g_return_if_fail (PLUMA_IS_WINDOW_ACTIVATABLE (activatable)); + + iface = PLUMA_WINDOW_ACTIVATABLE_GET_IFACE (activatable); + if (iface->update_state != NULL) + { + iface->update_state (activatable); + } +} diff --git a/pluma/pluma-window-activatable.h b/pluma/pluma-window-activatable.h new file mode 100644 index 00000000..de95b05d --- /dev/null +++ b/pluma/pluma-window-activatable.h @@ -0,0 +1,61 @@ +/* + * pluma-window-activatable.h + * This file is part of pluma + * + * Copyright (C) 2010 - Steve Frécinaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 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 Library 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 https://www.gnu.org/licenses/. + */ + +#ifndef __PLUMA_WINDOW_ACTIVATABLE_H__ +#define __PLUMA_WINDOW_ACTIVATABLE_H__ + +#include + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define PLUMA_TYPE_WINDOW_ACTIVATABLE (pluma_window_activatable_get_type ()) +#define PLUMA_WINDOW_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUMA_TYPE_WINDOW_ACTIVATABLE, PlumaWindowActivatable)) +#define PLUMA_WINDOW_ACTIVATABLE_IFACE(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), PLUMA_TYPE_WINDOW_ACTIVATABLE, PlumaWindowActivatableInterface)) +#define PLUMA_IS_WINDOW_ACTIVATABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUMA_TYPE_WINDOW_ACTIVATABLE)) +#define PLUMA_WINDOW_ACTIVATABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), PLUMA_TYPE_WINDOW_ACTIVATABLE, PlumaWindowActivatableInterface)) + +typedef struct _PlumaWindowActivatable PlumaWindowActivatable; /* dummy typedef */ +typedef struct _PlumaWindowActivatableInterface PlumaWindowActivatableInterface; + +struct _PlumaWindowActivatableInterface +{ + GTypeInterface g_iface; + + /* Virtual public methods */ + void (*activate) (PlumaWindowActivatable *activatable); + void (*deactivate) (PlumaWindowActivatable *activatable); + void (*update_state) (PlumaWindowActivatable *activatable); +}; + +/* + * Public methods + */ +GType pluma_window_activatable_get_type (void) G_GNUC_CONST; + +void pluma_window_activatable_activate (PlumaWindowActivatable *activatable); +void pluma_window_activatable_deactivate (PlumaWindowActivatable *activatable); +void pluma_window_activatable_update_state (PlumaWindowActivatable *activatable); + +G_END_DECLS + +#endif /* __PLUMA_WINDOW_ACTIVATABLE_H__ */ diff --git a/pluma/pluma-window.c b/pluma/pluma-window.c index 337af89c..e797b6e0 100644 --- a/pluma/pluma-window.c +++ b/pluma/pluma-window.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include "pluma-ui.h" @@ -57,6 +56,7 @@ #include "pluma-panel.h" #include "pluma-documents-panel.h" #include "pluma-plugins-engine.h" +#include "pluma-window-activatable.h" #include "pluma-enum-types.h" #include "pluma-dirs.h" #include "pluma-status-combo-box.h" @@ -919,7 +919,7 @@ set_sensitivity_according_to_tab (PlumaWindow *window, update_next_prev_doc_sensitivity (window, tab); - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static void @@ -2771,7 +2771,7 @@ sync_name (PlumaTab *tab, g_free (escaped_name); g_free (tip); - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static PlumaWindow * @@ -3167,7 +3167,7 @@ selection_changed (PlumaDocument *doc, editable && gtk_text_buffer_get_has_selection (GTK_TEXT_BUFFER (doc))); - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static void @@ -3176,7 +3176,7 @@ sync_languages_menu (PlumaDocument *doc, PlumaWindow *window) { update_languages_menu (window); - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static void @@ -3188,7 +3188,7 @@ readonly_changed (PlumaDocument *doc, sync_name (window->priv->active_tab, NULL, window); - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static void @@ -3196,7 +3196,7 @@ editable_changed (PlumaView *view, GParamSpec *arg1, PlumaWindow *window) { - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } static void @@ -3408,7 +3408,7 @@ notebook_tab_removed (PlumaNotebook *notebook, if (window->priv->num_tabs == 0) { - peas_extension_set_call (window->priv->extensions, "update_state", window); + peas_extension_set_call (window->priv->extensions, "update_state"); } update_window_state (window); @@ -4096,9 +4096,10 @@ pluma_window_init (PlumaWindow *window) pluma_debug_message (DEBUG_WINDOW, "Update plugins ui"); window->priv->extensions = peas_extension_set_new (PEAS_ENGINE (pluma_plugins_engine_get_default ()), - PEAS_TYPE_ACTIVATABLE, "object", window, NULL); - - peas_extension_set_call (window->priv->extensions, "activate"); + PLUMA_TYPE_WINDOW_ACTIVATABLE, + "window", + window, + NULL); g_signal_connect (window->priv->extensions, "extension-added", @@ -4109,8 +4110,10 @@ pluma_window_init (PlumaWindow *window) G_CALLBACK (on_extension_removed), window); - /* set visibility of panes. - * This needs to be done after plugins activatation */ + peas_extension_set_call (window->priv->extensions, "activate"); + + /* set visibility of panes. + This needs to be done after plugins activatation */ init_panels_visibility (window); update_sensitivity_according_to_open_tabs (window); -- cgit v1.2.1