/* BEGIN_COMMON_COPYRIGHT_HEADER * (c)LGPL2+ * * LXDE-Qt - a lightweight, Qt based, desktop toolset * http://razor-qt.org * * Copyright: 2012 Razor team * Authors: * Alexander Sokoloff * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * END_COMMON_COPYRIGHT_HEADER */ #include "plugin.h" #include "ilxqtpanelplugin.h" #include "lxqtpanel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // statically linked built-in plugins #include "../plugin-clock/lxqtclock.h" // clock extern void * loadPluginTranslation_clock_helper; #include "../plugin-desktopswitch/desktopswitch.h" // desktopswitch extern void * loadPluginTranslation_desktopswitch_helper; #include "../plugin-mainmenu/lxqtmainmenu.h" // mainmenu extern void * loadPluginTranslation_mainmenu_helper; #include "../plugin-quicklaunch/lxqtquicklaunchplugin.h" // quicklaunch extern void * loadPluginTranslation_quicklaunch_helper; #include "../plugin-showdesktop/showdesktop.h" // showdesktop extern void * loadPluginTranslation_showdesktop_helper; #include "../plugin-spacer/spacer.h" // spacer extern void * loadPluginTranslation_spacer_helper; #include "../plugin-statusnotifier/statusnotifier.h" // statusnotifier extern void * loadPluginTranslation_statusnotifier_helper; #include "../plugin-taskbar/lxqttaskbarplugin.h" // taskbar extern void * loadPluginTranslation_taskbar_helper; #include "../plugin-tray/lxqttrayplugin.h" // tray extern void * loadPluginTranslation_tray_helper; #include "../plugin-worldclock/lxqtworldclock.h" // worldclock extern void * loadPluginTranslation_worldclock_helper; QColor Plugin::mMoveMarkerColor= QColor(255, 0, 0, 255); /************************************************ ************************************************/ Plugin::Plugin(const LXQt::PluginInfo &desktopFile, const QString &settingsFile, const QString &settingsGroup, LXQtPanel *panel) : QFrame(panel), mDesktopFile(desktopFile), mPluginLoader(0), mPlugin(0), mPluginWidget(0), mAlignment(AlignLeft), mSettingsGroup(settingsGroup), mPanel(panel) { mSettings = new LXQt::Settings(settingsFile, QSettings::IniFormat, this); connect(mSettings, SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); mSettings->beginGroup(settingsGroup); mSettingsHash = calcSettingsHash(); setWindowTitle(desktopFile.name()); mName = desktopFile.name(); QStringList dirs; dirs << QProcessEnvironment::systemEnvironment().value("LXQTPANEL_PLUGIN_PATH").split(":"); dirs << PLUGIN_DIR; bool found = false; if(ILXQtPanelPluginLibrary const * pluginLib = findStaticPlugin(desktopFile.id())) { // this is a static plugin found = true; loadLib(pluginLib); } else { // this plugin is a dynamically loadable module QString baseName = QString("lib%1.so").arg(desktopFile.id()); foreach(QString dirName, dirs) { QFileInfo fi(QDir(dirName), baseName); if (fi.exists()) { found = true; if (loadModule(fi.absoluteFilePath())) break; } } } if (!isLoaded()) { if (!found) qWarning() << QString("Plugin %1 not found in the").arg(desktopFile.id()) << dirs; return; } setObjectName(mPlugin->themeId() + "Plugin"); // plugin handle for easy context menu setProperty("NeedsHandle", mPlugin->flags().testFlag(ILXQtPanelPlugin::NeedsHandle)); QString s = mSettings->value("alignment").toString(); // Retrun default value if (s.isEmpty()) { mAlignment = (mPlugin->flags().testFlag(ILXQtPanelPlugin::PreferRightAlignment)) ? Plugin::AlignRight : Plugin::AlignLeft; } else { mAlignment = (s.toUpper() == "RIGHT") ? Plugin::AlignRight : Plugin::AlignLeft; } if (mPluginWidget) { QGridLayout* layout = new QGridLayout(this); layout->setSpacing(0); layout->setMargin(0); layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); layout->addWidget(mPluginWidget, 0, 0); } saveSettings(); } /************************************************ ************************************************/ Plugin::~Plugin() { delete mPlugin; if (mPluginLoader) { mPluginLoader->unload(); delete mPluginLoader; } } void Plugin::setAlignment(Plugin::Alignment alignment) { mAlignment = alignment; saveSettings(); } /************************************************ ************************************************/ namespace { //helper types for static plugins storage & binary search typedef std::unique_ptr plugin_ptr_t; typedef std::tuple plugin_tuple_t; //NOTE: Please keep the plugins sorted by name while adding new plugins. //NOTE2: we need to reference some (dummy) symbol from (autogenerated) LXQtPluginTranslationLoader.cpp // to be not stripped (as unused/unreferenced) in static linking time static plugin_tuple_t const static_plugins[] = { #if defined(WITH_CLOCK_PLUGIN) std::make_tuple(QStringLiteral("clock"), plugin_ptr_t{new LXQtClockPluginLibrary}, loadPluginTranslation_clock_helper),// clock #endif #if defined(WITH_DESKTOPSWITCH_PLUGIN) std::make_tuple(QStringLiteral("desktopswitch"), plugin_ptr_t{new DesktopSwitchPluginLibrary}, loadPluginTranslation_desktopswitch_helper),// desktopswitch #endif #if defined(WITH_MAINMENU_PLUGIN) std::make_tuple(QStringLiteral("mainmenu"), plugin_ptr_t{new LXQtMainMenuPluginLibrary}, loadPluginTranslation_mainmenu_helper),// mainmenu #endif #if defined(WITH_QUICKLAUNCH_PLUGIN) std::make_tuple(QStringLiteral("quicklaunch"), plugin_ptr_t{new LXQtQuickLaunchPluginLibrary}, loadPluginTranslation_quicklaunch_helper),// quicklaunch #endif #if defined(WITH_SHOWDESKTOP_PLUGIN) std::make_tuple(QStringLiteral("showdesktop"), plugin_ptr_t{new ShowDesktopLibrary}, loadPluginTranslation_showdesktop_helper),// showdesktop #endif #if defined(WITH_SPACER_PLUGIN) std::make_tuple(QStringLiteral("spacer"), plugin_ptr_t{new SpacerPluginLibrary}, loadPluginTranslation_spacer_helper),// spacer #endif #if defined(WITH_STATUSNOTIFIER_PLUGIN) std::make_tuple(QStringLiteral("statusnotifier"), plugin_ptr_t{new StatusNotifierLibrary}, loadPluginTranslation_statusnotifier_helper),// statusnotifier #endif #if defined(WITH_TASKBAR_PLUGIN) std::make_tuple(QStringLiteral("taskbar"), plugin_ptr_t{new LXQtTaskBarPluginLibrary}, loadPluginTranslation_taskbar_helper),// taskbar #endif #if defined(WITH_TRAY_PLUGIN) std::make_tuple(QStringLiteral("tray"), plugin_ptr_t{new LXQtTrayPluginLibrary}, loadPluginTranslation_tray_helper),// tray #endif #if defined(WITH_WORLDCLOCK_PLUGIN) std::make_tuple(QStringLiteral("worldclock"), plugin_ptr_t{new LXQtWorldClockLibrary}, loadPluginTranslation_worldclock_helper),// worldclock #endif }; static constexpr plugin_tuple_t const * const plugins_begin = static_plugins; static constexpr plugin_tuple_t const * const plugins_end = static_plugins + sizeof (static_plugins) / sizeof (static_plugins[0]); struct assert_helper { assert_helper() { Q_ASSERT(std::is_sorted(plugins_begin, plugins_end , [] (plugin_tuple_t const & p1, plugin_tuple_t const & p2) -> bool { return std::get<0>(p1) < std::get<0>(p2); })); } }; static assert_helper h; } ILXQtPanelPluginLibrary const * Plugin::findStaticPlugin(const QString &libraryName) { // find a static plugin library by name -> binary search plugin_tuple_t const * plugin = std::lower_bound(plugins_begin, plugins_end, libraryName , [] (plugin_tuple_t const & plugin, QString const & name) -> bool { return std::get<0>(plugin) < name; }); if (plugins_end != plugin && libraryName == std::get<0>(*plugin)) return std::get<1>(*plugin).get(); return nullptr; } // load a plugin from a library bool Plugin::loadLib(ILXQtPanelPluginLibrary const * pluginLib) { ILXQtPanelPluginStartupInfo startupInfo; startupInfo.settings = mSettings; startupInfo.desktopFile = &mDesktopFile; startupInfo.lxqtPanel = mPanel; mPlugin = pluginLib->instance(startupInfo); if (!mPlugin) { qWarning() << QString("Can't load plugin \"%1\". Plugin can't build ILXQtPanelPlugin.").arg(mPluginLoader->fileName()); return false; } mPluginWidget = mPlugin->widget(); if (mPluginWidget) { mPluginWidget->setObjectName(mPlugin->themeId()); } this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); return true; } // load dynamic plugin from a *.so module bool Plugin::loadModule(const QString &libraryName) { mPluginLoader = new QPluginLoader(libraryName); if (!mPluginLoader->load()) { qWarning() << mPluginLoader->errorString(); return false; } QObject *obj = mPluginLoader->instance(); if (!obj) { qWarning() << mPluginLoader->errorString(); return false; } ILXQtPanelPluginLibrary* pluginLib= qobject_cast(obj); if (!pluginLib) { qWarning() << QString("Can't load plugin \"%1\". Plugin is not a ILXQtPanelPluginLibrary.").arg(mPluginLoader->fileName()); delete obj; return false; } return loadLib(pluginLib); } /************************************************ ************************************************/ QByteArray Plugin::calcSettingsHash() { QCryptographicHash hash(QCryptographicHash::Md5); QStringList keys = mSettings->allKeys(); foreach (const QString &key, keys) { hash.addData(key.toUtf8()); hash.addData(mSettings->value(key).toByteArray()); } return hash.result(); } /************************************************ ************************************************/ void Plugin::settingsChanged() { QByteArray hash = calcSettingsHash(); if (mSettingsHash != hash) { mSettingsHash = hash; mPlugin->settingsChanged(); } } /************************************************ ************************************************/ void Plugin::saveSettings() { mSettings->setValue("alignment", (mAlignment == AlignLeft) ? "Left" : "Right"); mSettings->setValue("type", mDesktopFile.id()); mSettings->sync(); } /************************************************ ************************************************/ void Plugin::contextMenuEvent(QContextMenuEvent *event) { mPanel->showPopupMenu(this); } /************************************************ ************************************************/ void Plugin::mousePressEvent(QMouseEvent *event) { switch (event->button()) { case Qt::LeftButton: mPlugin->activated(ILXQtPanelPlugin::Trigger); break; case Qt::MidButton: mPlugin->activated(ILXQtPanelPlugin::MiddleClick); break; default: break; } } /************************************************ ************************************************/ void Plugin::mouseDoubleClickEvent(QMouseEvent*) { mPlugin->activated(ILXQtPanelPlugin::DoubleClick); } /************************************************ ************************************************/ void Plugin::showEvent(QShowEvent *) { if (mPluginWidget) mPluginWidget->adjustSize(); } /************************************************ ************************************************/ QMenu *Plugin::popupMenu() const { QString name = this->name().replace("&", "&&"); QMenu* menu = new QMenu(windowTitle()); if (mPlugin->flags().testFlag(ILXQtPanelPlugin::HaveConfigDialog)) { QAction* configAction = new QAction( XdgIcon::fromTheme(QStringLiteral("preferences-other")), tr("Configure \"%1\"").arg(name), menu); menu->addAction(configAction); connect(configAction, SIGNAL(triggered()), this, SLOT(showConfigureDialog())); } QAction* moveAction = new QAction(XdgIcon::fromTheme("transform-move"), tr("Move \"%1\"").arg(name), menu); menu->addAction(moveAction); connect(moveAction, SIGNAL(triggered()), this, SIGNAL(startMove())); menu->addSeparator(); QAction* removeAction = new QAction( XdgIcon::fromTheme(QStringLiteral("list-remove")), tr("Remove \"%1\"").arg(name), menu); menu->addAction(removeAction); connect(removeAction, SIGNAL(triggered()), this, SLOT(requestRemove())); return menu; } /************************************************ ************************************************/ bool Plugin::isSeparate() const { return mPlugin->isSeparate(); } /************************************************ ************************************************/ bool Plugin::isExpandable() const { return mPlugin->isExpandable(); } /************************************************ ************************************************/ void Plugin::realign() { if (mPlugin) mPlugin->realign(); } /************************************************ ************************************************/ void Plugin::showConfigureDialog() { // store a pointer to each plugin using the plugins' names static QHash > refs; QDialog *dialog = refs[name()].data(); if (!dialog) { dialog = mPlugin->configureDialog(); refs[name()] = dialog; connect(this, SIGNAL(destroyed()), dialog, SLOT(close())); } if (!dialog) return; dialog->show(); dialog->raise(); dialog->activateWindow(); } /************************************************ ************************************************/ void Plugin::requestRemove() { emit remove(); deleteLater(); }