Commit d12db0b2 authored by Christian Hergert's avatar Christian Hergert

editor: add IdeEditorAddin

This addin interface is used to extend the editor perspective.
This can be handy over the workbench addin because it allows you
to write a bit less code and use some of the view tracking that
is specific to the editor perspective.
parent c125f11d
/* ide-editor-addin.c
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* 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 3 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 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 <http://www.gnu.org/licenses/>.
*/
#define G_LOG_DOMAIN "ide-editor-addin"
#include "editor/ide-editor-addin.h"
#include "editor/ide-editor-private.h"
/**
* SECTION:ide-editor-addin
* @title: IdeEditorAddin
* @short_description: Addins for the editor perspective
*
* The #IdeEditorAddin interface provides a simplified interface for
* plugins that want to perform operations in, or extend, the editor
* perspective.
*
* This differs from the #IdeWorkbenchAddin in that you are given access
* to the editor perspective directly. This can be convenient if all you
* need to do is add panels or perform view tracking of the current
* focus view.
*/
G_DEFINE_INTERFACE (IdeEditorAddin, ide_editor_addin, G_TYPE_OBJECT)
static void
ide_editor_addin_default_init (IdeEditorAddinInterface *iface)
{
}
/**
* ide_editor_addin_load:
* @self: an #IdeEditorAddin
* @perspective: an #IdeEditorPeprsective
*
* This method is called to load the addin.
*
* The addin should add any necessary UI components.
*
* Since: 3.26
*/
void
ide_editor_addin_load (IdeEditorAddin *self,
IdeEditorPerspective *perspective)
{
g_return_if_fail (IDE_IS_EDITOR_ADDIN (self));
g_return_if_fail (IDE_IS_EDITOR_PERSPECTIVE (perspective));
if (IDE_EDITOR_ADDIN_GET_IFACE (self)->load)
IDE_EDITOR_ADDIN_GET_IFACE (self)->load (self, perspective);
}
/**
* ide_editor_addin_unload:
* @self: an #IdeEditorAddin
* @perspective: an #IdeEditorPerspective
*
* This method is called to unload the addin.
*
* The addin is responsible for undoing anything it setup in load
* and cancel any in-flight or pending tasks immediately.
*
* Since: 3.26
*/
void
ide_editor_addin_unload (IdeEditorAddin *self,
IdeEditorPerspective *perspective)
{
g_return_if_fail (IDE_IS_EDITOR_ADDIN (self));
g_return_if_fail (IDE_IS_EDITOR_PERSPECTIVE (perspective));
if (IDE_EDITOR_ADDIN_GET_IFACE (self)->unload)
IDE_EDITOR_ADDIN_GET_IFACE (self)->unload (self, perspective);
}
/**
* ide_editor_addin_view_set:
* @self: an #IdeEditorAddin
* @view: (nullable): an #IdeLayoutView or %NULL
*
* This function is called when the current view has changed in the
* editor perspective. This could happen when the user focus another
* view, either with the keyboard, mouse, touch, or by opening a new
* buffer.
*
* Note that @view may not be an #IdeEditorView, so consumers of this
* interface should take appropriate action based on the type.
*
* When the last view is removed, @view will be %NULL to indicate to the
* addin that there is no active view.
*
* Since: 3.26
*/
void
ide_editor_addin_view_set (IdeEditorAddin *self,
IdeLayoutView *view)
{
g_return_if_fail (IDE_IS_EDITOR_ADDIN (self));
g_return_if_fail (!view || IDE_IS_LAYOUT_VIEW (view));
if (IDE_EDITOR_ADDIN_GET_IFACE (self)->view_set)
IDE_EDITOR_ADDIN_GET_IFACE (self)->view_set (self, view);
}
/**
* ide_editor_addin_find_by_module_name:
* @editor: an #IdeEditorPerspective
* @module_name: the module name of the addin
*
* This function allows locating an #IdeEditorAddin that is attached
* to the #IdeEditorPerspective by the addin module name. The module name
* should match the value specified in the ".plugin" module definition.
*
* Returns: (transfer none) (nullable): An #IdeEditorAddin or %NULL
*/
IdeEditorAddin *
ide_editor_addin_find_by_module_name (IdeEditorPerspective *editor,
const gchar *module_name)
{
PeasExtension *ret = NULL;
PeasPluginInfo *plugin_info;
g_return_val_if_fail (IDE_IS_EDITOR_PERSPECTIVE (editor), NULL);
g_return_val_if_fail (module_name != NULL, NULL);
plugin_info = peas_engine_get_plugin_info (peas_engine_get_default (), module_name);
if (plugin_info != NULL)
ret = peas_extension_set_get_extension (editor->addins, plugin_info);
else
g_warning ("No such module found \"%s\"", module_name);
return ret ? IDE_EDITOR_ADDIN (ret) : NULL;
}
/* ide-editor-addin.h
*
* Copyright (C) 2017 Christian Hergert <chergert@redhat.com>
*
* 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 3 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 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "editor/ide-editor-perspective.h"
#include "layout/ide-layout-view.h"
G_BEGIN_DECLS
#define IDE_TYPE_EDITOR_ADDIN (ide_editor_addin_get_type())
G_DECLARE_INTERFACE (IdeEditorAddin, ide_editor_addin, IDE, EDITOR_ADDIN, GObject)
struct _IdeEditorAddinInterface
{
GTypeInterface parent_iface;
void (*load) (IdeEditorAddin *self,
IdeEditorPerspective *perspective);
void (*unload) (IdeEditorAddin *self,
IdeEditorPerspective *perspective);
void (*view_set) (IdeEditorAddin *self,
IdeLayoutView *view);
};
void ide_editor_addin_load (IdeEditorAddin *self,
IdeEditorPerspective *perspective);
void ide_editor_addin_unload (IdeEditorAddin *self,
IdeEditorPerspective *perspective);
void ide_editor_addin_view_set (IdeEditorAddin *self,
IdeLayoutView *view);
IdeEditorAddin *ide_editor_addin_find_by_module_name (IdeEditorPerspective *editor,
const gchar *module_name);
G_END_DECLS
......@@ -23,6 +23,7 @@
#include "buffers/ide-buffer.h"
#include "buffers/ide-buffer-manager.h"
#include "diagnostics/ide-source-location.h"
#include "editor/ide-editor-addin.h"
#include "editor/ide-editor-perspective.h"
#include "editor/ide-editor-private.h"
#include "editor/ide-editor-properties.h"
......@@ -47,6 +48,107 @@ static void ide_editor_perspective_focus_location_full (IdeEditorPerspective
G_DEFINE_TYPE_WITH_CODE (IdeEditorPerspective, ide_editor_perspective, IDE_TYPE_LAYOUT,
G_IMPLEMENT_INTERFACE (IDE_TYPE_PERSPECTIVE, perspective_iface_init))
static void
ide_editor_perspective_addin_added (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
PeasExtension *exten,
gpointer user_data)
{
IdeEditorPerspective *self = user_data;
IdeEditorAddin *addin = (IdeEditorAddin *)exten;
IdeLayoutView *view;
g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));
g_assert (IDE_IS_EDITOR_ADDIN (addin));
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
ide_editor_addin_load (addin, self);
view = ide_layout_grid_get_current_view (self->grid);
if (view != NULL)
ide_editor_addin_view_set (addin, view);
}
static void
ide_editor_perspective_addin_removed (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
PeasExtension *exten,
gpointer user_data)
{
IdeEditorPerspective *self = user_data;
IdeEditorAddin *addin = (IdeEditorAddin *)exten;
IdeLayoutView *view;
g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));
g_assert (IDE_IS_EDITOR_ADDIN (addin));
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
view = ide_layout_grid_get_current_view (self->grid);
if (view != NULL)
ide_editor_addin_view_set (addin, NULL);
ide_editor_addin_unload (addin, self);
}
static void
ide_editor_perspective_hierarchy_changed (GtkWidget *widget,
GtkWidget *old_toplevel)
{
IdeEditorPerspective *self = (IdeEditorPerspective *)widget;
g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));
g_assert (!old_toplevel || GTK_IS_WIDGET (old_toplevel));
if (self->addins == NULL)
{
GtkWidget *toplevel;
/*
* If we just got a new toplevel and it is a workbench,
* and we have not yet created our addins, do so now.
*/
toplevel = gtk_widget_get_ancestor (widget, IDE_TYPE_WORKBENCH);
if (toplevel != NULL)
{
self->addins = peas_extension_set_new (peas_engine_get_default (),
IDE_TYPE_EDITOR_ADDIN,
NULL);
g_signal_connect (self->addins,
"extension-added",
G_CALLBACK (ide_editor_perspective_addin_added),
self);
g_signal_connect (self->addins,
"extension-removed",
G_CALLBACK (ide_editor_perspective_addin_removed),
self);
peas_extension_set_foreach (self->addins,
ide_editor_perspective_addin_added,
self);
}
}
}
static void
ide_editor_perspective_addins_view_set (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
PeasExtension *exten,
gpointer user_data)
{
IdeEditorAddin *addin = (IdeEditorAddin *)exten;
IdeLayoutView *view = user_data;
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_EDITOR_ADDIN (addin));
g_assert (!view || IDE_IS_LAYOUT_VIEW (view));
ide_editor_addin_view_set (addin, view);
}
static void
ide_editor_perspective_notify_current_view (IdeEditorPerspective *self,
GParamSpec *pspec,
......@@ -64,6 +166,10 @@ ide_editor_perspective_notify_current_view (IdeEditorPerspective *self,
ide_editor_properties_set_view (self->properties, IDE_EDITOR_VIEW (view));
else
ide_editor_properties_set_view (self->properties, NULL);
peas_extension_set_foreach (self->addins,
ide_editor_perspective_addins_view_set,
view);
}
static void
......@@ -106,6 +212,18 @@ ide_editor_perspective_create_edge (DzlDockBin *dock_bin,
return DZL_DOCK_BIN_CLASS (ide_editor_perspective_parent_class)->create_edge (dock_bin, edge);
}
static void
ide_editor_perspective_destroy (GtkWidget *widget)
{
IdeEditorPerspective *self = (IdeEditorPerspective *)widget;
g_assert (IDE_IS_EDITOR_PERSPECTIVE (self));
g_clear_object (&self->addins);
GTK_WIDGET_CLASS (ide_editor_perspective_parent_class)->destroy (widget);
}
static void
ide_editor_perspective_class_init (IdeEditorPerspectiveClass *klass)
{
......@@ -113,6 +231,9 @@ ide_editor_perspective_class_init (IdeEditorPerspectiveClass *klass)
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
DzlDockBinClass *dock_bin_class = DZL_DOCK_BIN_CLASS (klass);
widget_class->destroy = ide_editor_perspective_destroy;
widget_class->hierarchy_changed = ide_editor_perspective_hierarchy_changed;
container_class->add = ide_editor_perspective_add;
dock_bin_class->create_edge = ide_editor_perspective_create_edge;
......
......@@ -72,6 +72,7 @@ G_BEGIN_DECLS
#include "diagnostics/ide-source-range.h"
#include "doap/ide-doap-person.h"
#include "doap/ide-doap.h"
#include "editor/ide-editor-addin.h"
#include "editor/ide-editor-perspective.h"
#include "editor/ide-editor-sidebar.h"
#include "editor/ide-editor-view-addin.h"
......
......@@ -98,6 +98,7 @@ libide_public_headers = [
'directory/ide-directory-vcs.h',
'doap/ide-doap-person.h',
'doap/ide-doap.h',
'editor/ide-editor-addin.h',
'editor/ide-editor-perspective.h',
'editor/ide-editor-sidebar.h',
'editor/ide-editor-view-addin.h',
......@@ -294,6 +295,7 @@ libide_public_sources = [
'directory/ide-directory-vcs.c',
'doap/ide-doap-person.c',
'doap/ide-doap.c',
'editor/ide-editor-addin.c',
'editor/ide-editor-perspective.c',
'editor/ide-editor-sidebar.c',
'editor/ide-editor-view-addin.c',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment