Commit 2c1a4113 authored by Tomaz  Canabrava's avatar Tomaz Canabrava Committed by Tomaz Canabrava
Browse files

Implement a Base system for plugins within Konsole

This commit introduces a plugins sytem for konsole, so we can
extend the application without touching the core. Currently
there's a testcase plugin (in the next commit) that handles
ssh connections and will serve as a base introduction on how
to write plugins for konsole.

Things we need to keep in mind when developing a plugin for
konsole:
- We can have more than a mainwindow, so if the plugin creates
widgets, it needs to create the widget per window
- We can have multiple tabs / multiple TerminalDisplays so always
check what terminal display you are triggering the action (using
activeTerminalDisplay())

From the mainWindow you can get the activeTerminalDisplay, from
the terminalDisplay you can get the Session, the VT102Emulation and
the Screen.

Then you can go crazy.
parent 1fa7b3a3
<?xml version="1.0"?>
<!DOCTYPE gui SYSTEM "kpartgui.dtd">
<gui name="konsole" version="14">
<gui name="konsole" version="17">
<MenuBar>
<Menu name="file"><text>File</text>
<Action name="new-window"/>
......@@ -46,6 +46,10 @@
<Action name="configure-notifications"/>
<Action name="configure-settings"/>
</Menu>
<Menu name="plugins">
<text>Plugins</text>
<ActionList name="plugin-submenu" />
</Menu>
<Menu name="help"><text>Help</text>
</Menu>
</MenuBar>
......
......@@ -34,6 +34,8 @@
#include "terminalDisplay/TerminalDisplay.h"
#include "widgets/ViewContainer.h"
#include "pluginsystem/IKonsolePlugin.h"
using namespace Konsole;
Application::Application(QSharedPointer<QCommandLineParser> parser,
......@@ -42,6 +44,7 @@ Application::Application(QSharedPointer<QCommandLineParser> parser,
m_parser(parser),
m_customCommand(customCommand)
{
m_pluginManager.loadAllPlugins();
}
void Application::populateCommandLineParser(QCommandLineParser *parser)
......@@ -164,6 +167,8 @@ MainWindow *Application::newMainWindow()
&Konsole::Application::createWindow);
connect(window, &Konsole::MainWindow::terminalsDetached, this, &Konsole::Application::detachTerminals);
m_pluginManager.registerMainWindow(window);
return window;
}
......
......@@ -13,6 +13,10 @@
// Konsole
#include "widgets/ViewSplitter.h"
#include "pluginsystem/PluginManager.h"
#include "konsole_export.h"
namespace Konsole {
class MainWindow;
class Session;
......@@ -30,7 +34,7 @@ class Profile;
* The factory used to create new terminal sessions can be retrieved using
* the sessionManager() accessor.
*/
class Application : public QObject
class KONSOLE_EXPORT Application : public QObject
{
Q_OBJECT
......@@ -79,6 +83,8 @@ private:
MainWindow *_backgroundInstance;
QSharedPointer<QCommandLineParser> m_parser;
QStringList m_customCommand;
PluginManager m_pluginManager;
};
}
#endif // APPLICATION_H
......@@ -244,10 +244,8 @@ set_target_properties(konsoleprivate PROPERTIES
install(TARGETS konsoleprivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
set(konsole_SRCS
Application.cpp
add_library(konsoleapp SHARED Application.cpp
MainWindow.cpp
main.cpp
settings/ConfigurationDialog.cpp
settings/ConfigDialogButtonGroupManager.cpp
settings/TemporaryFilesSettings.cpp
......@@ -255,9 +253,32 @@ set(konsole_SRCS
settings/ProfileSettings.cpp
settings/TabBarSettings.cpp
settings/ThumbnailsSettings.cpp
pluginsystem/IKonsolePlugin.cpp
pluginsystem/PluginManager.cpp
delegates/ProfileShortcutDelegate.cpp
)
target_link_libraries(konsoleapp
konsoleprivate
KF5::XmlGui
KF5::WindowSystem
KF5::Bookmarks
KF5::I18n
KF5::KIOWidgets
KF5::NotifyConfig
KF5::Crash
)
set_target_properties(konsoleapp PROPERTIES
VERSION ${KONSOLEPRIVATE_VERSION_STRING}
SOVERSION ${KONSOLEPRIVATE_SOVERSION}
)
install(TARGETS konsoleapp ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
set(konsole_SRCS
main.cpp
)
# Sets the icon on Windows and OSX
ecm_add_app_icon(konsole ICONS ${ICONS_SRCS})
......@@ -265,6 +286,7 @@ ecm_add_app_icon(konsole ICONS ${ICONS_SRCS})
add_executable(konsole ${konsole_SRCS})
target_link_libraries(konsole
konsoleprivate
konsoleapp
KF5::XmlGui
KF5::WindowSystem
KF5::Bookmarks
......
......@@ -494,6 +494,13 @@ void MainWindow::newTab()
createSession(defaultProfile, activeSessionDir());
}
void MainWindow::addPlugin(IKonsolePlugin *plugin)
{
_plugins.append(plugin);
connect(_viewManager, &Konsole::ViewManager::activeViewChanged, plugin,
&IKonsolePlugin::activeViewChanged);
}
void MainWindow::cloneTab()
{
Q_ASSERT(_pluggedController);
......@@ -524,6 +531,7 @@ Session *MainWindow::createSession(Profile::Ptr profile, const QString &director
// don't like this happening
auto newView = _viewManager->createView(session);
_viewManager->activeContainer()->addView(newView);
return session;
}
......@@ -968,11 +976,11 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *event)
return KXmlGuiWindow::eventFilter(obj, event);
}
bool MainWindow::focusNextPrevChild(bool)
bool MainWindow::focusNextPrevChild(bool v)
{
// In stand-alone konsole, always disable implicit focus switching
// through 'Tab' and 'Shift+Tab'
//
// Kpart is another different story
return false;
if (qobject_cast<TerminalDisplay*>(focusWidget())) {
return false;
}
return QMainWindow::focusNextPrevChild(v);
}
......@@ -18,6 +18,10 @@
// Konsole
#include "widgets/ViewSplitter.h"
#include "pluginsystem/IKonsolePlugin.h"
#include "konsole_export.h"
class QAction;
class KActionMenu;
class KToggleAction;
......@@ -41,7 +45,7 @@ class BookmarkHandler;
*
* Do not construct new main windows directly, use Application's newMainWindow() method.
*/
class MainWindow : public KXmlGuiWindow
class KONSOLE_EXPORT MainWindow : public KXmlGuiWindow
{
Q_OBJECT
......@@ -93,6 +97,16 @@ public:
*/
void setRemoveWindowTitleBarAndFrame(bool frameless);
/**
* A reference to a plugin on the system.
*/
void addPlugin(IKonsolePlugin *plugin);
/**
* creates a new tab for the main window
*/
void newTab();
Q_SIGNALS:
/**
......@@ -128,7 +142,6 @@ protected:
bool focusNextPrevChild(bool next) override;
private Q_SLOTS:
void newTab();
void cloneTab();
void newWindow();
void showManageProfilesDialog();
......@@ -183,7 +196,7 @@ private:
KActionMenu *_newTabMenuAction;
QPointer<SessionController> _pluggedController;
QList<IKonsolePlugin*> _plugins;
bool _menuBarInitialVisibility;
bool _menuBarInitialVisibilityApplied;
bool _blurEnabled = false;
......
/* This file was part of the KDE libraries
SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "IKonsolePlugin.h"
#include <QMainWindow>
#include "MainWindow.h"
namespace Konsole {
struct IKonsolePlugin::Private {
QString name;
QList<QMainWindow*> mainWindowList;
};
IKonsolePlugin::IKonsolePlugin(QObject *parent, const QVariantList &args) :
d(std::make_unique<IKonsolePlugin::Private>())
{
Q_UNUSED(parent)
Q_UNUSED(args)
}
IKonsolePlugin::~IKonsolePlugin() = default;
void IKonsolePlugin::setName(const QString& name)
{
d->name = name;
}
QString IKonsolePlugin::name() const {
return d->name;
}
void IKonsolePlugin::addMainWindow(Konsole::MainWindow *mainWindow)
{
d->mainWindowList.append(mainWindow);
createWidgetsForMainWindow(mainWindow);
}
void IKonsolePlugin::removeMainWindow(Konsole::MainWindow *mainWindow)
{
d->mainWindowList.removeOne(mainWindow);
}
}
/* This file was part of the KDE libraries
SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef IKONSOLEPLUGIN_H
#define IKONSOLEPLUGIN_H
#include <QList>
#include <QDockWidget>
#include <QObject>
#include <terminalDisplay/TerminalDisplay.h>
#include <KXMLGUIClient>
#include <KPluginFactory>
#include <KExportPlugin>
#include <memory>
#include "konsole_export.h"
namespace Konsole {
class MainWindow;
class KONSOLE_EXPORT IKonsolePlugin : public QObject {
Q_OBJECT
public:
IKonsolePlugin(QObject *parent, const QVariantList &args);
~IKonsolePlugin();
QString name() const;
// Usable only from PluginManager, please don't use.
void addMainWindow(Konsole::MainWindow *mainWindow);
void removeMainWindow(Konsole::MainWindow *mainWindow);
virtual void createWidgetsForMainWindow(Konsole::MainWindow *mainWindow) = 0;
virtual void activeViewChanged(Konsole::SessionController *controller) = 0;
virtual QList<QAction*> menuBarActions(Konsole::MainWindow* mainWindow) const { return {}; };
protected:
void setName(const QString& pluginName);
private:
struct Private;
std::unique_ptr<Private> d;
};
}
#endif
/* This file was part of the KDE libraries
SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "PluginManager.h"
#include "IKonsolePlugin.h"
#include "MainWindow.h"
#include <KPluginMetaData>
namespace Konsole {
struct PluginManagerPrivate {
std::vector<IKonsolePlugin*> plugins;
};
PluginManager::PluginManager()
: d(std::make_unique<PluginManagerPrivate>())
{
}
PluginManager::~PluginManager()
{
qDeleteAll(d->plugins);
}
void PluginManager::loadAllPlugins()
{
QVector<KPluginMetaData> pluginMetaData = KPluginLoader::findPlugins(QStringLiteral("konsoleplugins"));
for(const auto &metaData : pluginMetaData) {
KPluginLoader pluginLoader(metaData.fileName());
KPluginFactory *factory = pluginLoader.factory();
if (!factory) {
continue;
}
auto *plugin = factory->create<IKonsolePlugin>();
if (!plugin) {
continue;
}
d->plugins.push_back(plugin);
}
}
void PluginManager::registerMainWindow(Konsole::MainWindow* window)
{
window->unplugActionList(QStringLiteral("plugin-submenu"));
QList<QAction*> internalPluginSubmenus;
for (auto *plugin : d->plugins) {
plugin->addMainWindow(window);
internalPluginSubmenus.append(plugin->menuBarActions(window));
window->addPlugin(plugin);
}
window->plugActionList(QStringLiteral("plugin-submenu"), internalPluginSubmenus);
}
std::vector<IKonsolePlugin*> PluginManager::plugins() const
{
return d->plugins;
}
}
/* This file was part of the KDE libraries
SPDX-FileCopyrightText: 2021 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef PLUGINMANAGER_H
#define PLUGINMANAGER_H
#include <QObject>
#include <QList>
#include <memory>
#include <KService>
#include "konsole_export.h"
namespace Konsole {
class IKonsolePlugin;
class MainWindow;
struct PluginManagerPrivate;
class KONSOLE_EXPORT PluginManager : public QObject {
Q_OBJECT
public:
PluginManager();
~PluginManager();
void loadAllPlugins();
void registerMainWindow(Konsole::MainWindow* window);
std::vector<IKonsolePlugin*> plugins() const;
private:
std::unique_ptr<PluginManagerPrivate> d;
};
}
#endif
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