diff --git a/CMakeLists.txt b/CMakeLists.txt index 8211298..8b59bdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,120 +1,120 @@ cmake_minimum_required(VERSION 3.0) project(libksysguard) set(PROJECT_VERSION "5.14.80") set(PROJECT_VERSION_MAJOR 5) # check with non-Plasma consumers (e.g. KDevelop) before bumping these versions set(QT_MIN_VERSION "5.5.0") set(KF5_MIN_VERSION "5.30.0") find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMAddTests) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMQtDeclareLoggingCategory) include(CMakePackageConfigHelpers) include(CheckIncludeFiles) include(CheckLibraryExists) include(FeatureSummary) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED CONFIG COMPONENTS DBus Network Widgets) -find_package(Qt5WebKitWidgets ${QT_MIN_VERSION} CONFIG) -set_package_properties(Qt5WebKitWidgets PROPERTIES - URL "git://gitorious.org/qt/qtwebkit.git" - DESCRIPTION "Qt Webkit module (web browsing engine)" +find_package(Qt5WebEngineWidgets ${QT_MIN_VERSION} CONFIG) +set_package_properties(Qt5WebEngineWidgets PROPERTIES + URL "git://code.qt.org/qt/qtwebenginewidgets.git" + DESCRIPTION "Qt WebEngine module (web browsing engine)" TYPE OPTIONAL PURPOSE "Used by the HTML-based GUI ksysguard library" ) find_package(KF5 REQUIRED COMPONENTS CoreAddons Config I18n WindowSystem Completion Auth WidgetsAddons IconThemes ConfigWidgets Service GlobalAccel KIO) find_package(KF5 OPTIONAL_COMPONENTS Plasma) set_package_properties(KF5Plasma PROPERTIES URL "https://cgit.kde.org/plasma-framework.git/" DESCRIPTION "The library of the plasma project" TYPE OPTIONAL PURPOSE "Used by signalplotter to use Plasma themes" ) find_package(ZLIB REQUIRED) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Support for gzip compressed files and data streams" URL "http://www.zlib.net" TYPE REQUIRED ) check_library_exists(c clock_gettime "time.h" HAVE_CLOCK_GETTIME_C) ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX KSYSGUARD VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/ksysguard_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5SysGuardConfigVersion.cmake" SOVERSION 7 ) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" TYPE OPTIONAL PURPOSE "Required for building the X11 based workspace" ) if(X11_FOUND) find_package(Qt5X11Extras REQUIRED) find_library(X11_XRes_LIB XRes ${X11_LIB_SEARCH_PATH}) find_path(X11_XRes_INCLUDE_PATH X11/extensions/XRes.h ${X11_INC_SEARCH_PATH}) if(X11_XRes_LIB AND X11_XRes_INCLUDE_PATH) set(X11_XRes_FOUND TRUE) endif() endif() set(HAVE_X11 ${X11_FOUND}) set(HAVE_XRES ${X11_XRes_FOUND}) -set(HAVE_QTWEBKITWIDGETS ${Qt5WebKitWidgets_FOUND}) +set(HAVE_QTWEBENGINEWIDGETS ${Qt5WebEngineWidgets_FOUND}) configure_file(config-ksysguard.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ksysguard.h ) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_definitions(-DQT_USE_QSTRINGBUILDER) add_definitions(-DQT_NO_CAST_FROM_ASCII) add_definitions(-DQT_NO_CAST_TO_ASCII) add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) #add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_subdirectory( lsofui ) add_subdirectory( processcore ) add_subdirectory( processui ) if (KF5Plasma_FOUND) add_subdirectory( signalplotter ) endif() add_subdirectory( ksgrd ) if(BUILD_TESTING) add_subdirectory( tests ) endif() install(DIRECTORY scripts/ DESTINATION ${KDE_INSTALL_DATADIR}/ksysguard/scripts) set(CMAKECONFIG_INSTALL_DIR ${KDE_INSTALL_LIBDIR}/cmake/KF5SysGuard) configure_package_config_file(KF5SysGuardConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/KF5SysGuardConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/KF5SysGuardConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/KF5SysGuardConfigVersion.cmake DESTINATION ${CMAKECONFIG_INSTALL_DIR}) install(EXPORT libksysguardLibraryTargets NAMESPACE KF5:: DESTINATION ${CMAKECONFIG_INSTALL_DIR} FILE KF5SysGuardLibraryTargets.cmake ) install(FILES libksysguard.categories DESTINATION ${KDE_INSTALL_CONFDIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/config-ksysguard.h.cmake b/config-ksysguard.h.cmake index e5b8609..ad648f1 100644 --- a/config-ksysguard.h.cmake +++ b/config-ksysguard.h.cmake @@ -1,17 +1,17 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_PTRACE_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_ENDIAN_H 1 /* Define to 1 if you have the header file. */ #cmakedefine HAVE_BYTESWAP_H 1 /* Define to 1 if you have the X11 xres file */ #cmakedefine HAVE_XRES 1 -/* Define if you have QtWebKitWidgets */ -#cmakedefine01 HAVE_QTWEBKITWIDGETS +/* Define if you have QtWebEngineWidgets */ +#cmakedefine01 HAVE_QTWEBENGINEWIDGETS /* Define if you have X11 at all */ #cmakedefine01 HAVE_X11 diff --git a/processui/CMakeLists.txt b/processui/CMakeLists.txt index b1dbebe..72ad79d 100644 --- a/processui/CMakeLists.txt +++ b/processui/CMakeLists.txt @@ -1,94 +1,94 @@ add_definitions(-DTRANSLATION_DOMAIN=\"processui\") check_include_files(sys/endian.h HAVE_SYS_ENDIAN_H) check_include_files(byteswap.h HAVE_BYTESWAP_H) set(ksysguard_WIDGETS "ksysguard.widgets") set(processui_LIB_SRCS ksysguardprocesslist.cpp ProcessFilter.cpp ProcessModel.cpp ReniceDlg.cpp KTextEditVT.cpp scripting.cpp ) ecm_qt_declare_logging_category(processui_LIB_SRCS HEADER processui_debug.h IDENTIFIER LIBKSYSGUARD_PROCESSUI CATEGORY_NAME org.kde.libksysguard.processui) ki18n_wrap_ui( processui_LIB_SRCS ReniceDlgUi.ui ProcessWidgetUI.ui ) add_library(processui ${processui_LIB_SRCS}) add_library(KF5::ProcessUi ALIAS processui) if(X11_XRes_FOUND) target_link_libraries(processui PRIVATE ${X11_XRes_LIB} ${X11_LIBRARIES}) include_directories(${X11_XRes_INCLUDE_PATH}) endif() target_link_libraries(processui PUBLIC KF5::ProcessCore Qt5::Widgets KF5::ConfigCore PRIVATE Qt5::DBus KF5::I18n KF5::WindowSystem KF5::Auth KF5::Completion KF5::ConfigWidgets KF5::WidgetsAddons KF5::IconThemes KF5::GlobalAccel KF5::Service KF5::KIOWidgets ) target_include_directories(processui PUBLIC "$" "$" ) if(X11_FOUND) target_link_libraries(processui PRIVATE Qt5::X11Extras KF5::WindowSystem) endif() -if(Qt5WebKitWidgets_FOUND) - target_link_libraries(processui PRIVATE Qt5::WebKitWidgets) +if(Qt5WebEngineWidgets_FOUND) + target_link_libraries(processui PRIVATE Qt5::WebEngineWidgets) endif() if(NOT HAVE_CLOCK_GETTIME_C) target_link_libraries(processui PRIVATE rt) endif() set_target_properties(processui PROPERTIES VERSION ${KSYSGUARD_VERSION_STRING} SOVERSION ${KSYSGUARD_SOVERSION} EXPORT_NAME ProcessUi ) install(TARGETS processui EXPORT libksysguardLibraryTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) #---------------------- # kde4_add_widget_files(ksysguardwidgets_PART_SRCS ${ksysguard_WIDGETS}) # # add_library(ksysguardwidgets MODULE ${ksysguardwidgets_PART_SRCS}) # # target_link_libraries(ksysguardwidgets ${KDE4_KDEUI_LIBS} processui) # # install(TARGETS ksysguardwidgets DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/designer ) install( FILES ProcessModel.h ProcessFilter.h KTextEditVT.h ksysguardprocesslist.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/ksysguard/processui COMPONENT Devel ) diff --git a/processui/scripting.cpp b/processui/scripting.cpp index fd2200b..e0b4ed0 100644 --- a/processui/scripting.cpp +++ b/processui/scripting.cpp @@ -1,232 +1,322 @@ /* KSysGuard, the KDE System Guard - Copyright (c) 2009 John Tapsell + Copyright (c) 2009 John Tapsell + Copyright (c) 2018 Fabian Vogt This library 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 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "scripting.h" #include #include #include #include #include #include #include #include #include #include "processes.h" #include "ksysguardprocesslist.h" #include #include #include #include #include #include -#if HAVE_QTWEBKITWIDGETS -#include -#include +#if HAVE_QTWEBENGINEWIDGETS +#include +#include +#include +#include +#include +#include #endif +class RemoteUrlInterceptor : public QWebEngineUrlRequestInterceptor { +public: + RemoteUrlInterceptor(QObject *parent) : QWebEngineUrlRequestInterceptor(parent) {} + void interceptRequest(QWebEngineUrlRequestInfo &info) override + { + // Block non-GET/HEAD requests + if(!QStringList({QStringLiteral("GET"), QStringLiteral("HEAD")}) + .contains(QString::fromLatin1(info.requestMethod()))) + info.block(true); + + // Block remote URLs + if(!QStringList({QStringLiteral("blob"), QStringLiteral("data"), + QStringLiteral("file")}).contains(info.requestUrl().scheme())) + info.block(true); + } +}; + class ScriptingHtmlDialog : public QDialog { public: ScriptingHtmlDialog(QWidget *parent) : QDialog(parent) { QDialogButtonBox *buttonBox = new QDialogButtonBox(this); buttonBox->setStandardButtons(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); -#if HAVE_QTWEBKITWIDGETS +#if HAVE_QTWEBENGINEWIDGETS QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(&m_webView); layout->addWidget(buttonBox); setLayout(layout); - (void)minimumSizeHint(); //Force the dialog to be laid out now layout->setContentsMargins(0,0,0,0); - m_webView.settings()->setOfflineStoragePath(QString()); - m_webView.settings()->setObjectCacheCapacities(0,0,0); - m_webView.settings()->setAttribute(QWebSettings::PluginsEnabled, false); - m_webView.settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false); - m_webView.page()->setNetworkAccessManager(nullptr); //Disable talking to remote servers - m_webView.page()->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded); - m_webView.page()->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded); - - // inject a style sheet that follows system colors, otherwise we might end up with black text on dark gray background - const QString styleSheet = QStringLiteral( - "body { background: %1; color: %2; }" \ - "a { color: %3; }" \ - "a:visited { color: %4; } " - ).arg(palette().background().color().name(), - palette().text().color().name(), - palette().link().color().name(), - palette().linkVisited().color().name()); - - // you can only provide a user style sheet url, so we turn it into a data url here - const QUrl dataUrl(QStringLiteral("data:text/css;charset=utf-8;base64,") + QString::fromLatin1(styleSheet.toUtf8().toBase64())); - - m_webView.settings()->setUserStyleSheetUrl(dataUrl); - + m_webView.settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); + m_webView.page()->profile()->setRequestInterceptor(new RemoteUrlInterceptor(this)); #endif } -#if HAVE_QTWEBKITWIDGETS - QWebView *webView() { +#if HAVE_QTWEBENGINEWIDGETS + QWebEngineView *webView() { return &m_webView; } protected: - QWebView m_webView; + QWebEngineView m_webView; #endif }; ProcessObject::ProcessObject(ProcessModel *model, int pid) { mModel = model; mPid = pid; } bool ProcessObject::fileExists(const QString &filename) { QFileInfo fileInfo(filename); return fileInfo.exists(); } QString ProcessObject::readFile(const QString &filename) { QFile file(filename); if(!file.open(QIODevice::ReadOnly)) return QString(); QTextStream stream(&file); QString contents = stream.readAll(); file.close(); return contents; } Scripting::Scripting(KSysGuardProcessList * parent) : QWidget(parent), mProcessList(parent) { mScriptingHtmlDialog = nullptr; loadContextMenu(); } void Scripting::runScript(const QString &path, const QString &name) { //Record the script name and path for use in the script helper functions mScriptPath = path; mScriptName = name; -#if HAVE_QTWEBKITWIDGETS +#if HAVE_QTWEBENGINEWIDGETS QUrl fileName = QUrl::fromLocalFile(path + QStringLiteral("index.html")); if(!mScriptingHtmlDialog) { mScriptingHtmlDialog = new ScriptingHtmlDialog(this); + mWebChannel = new QWebChannel(mScriptingHtmlDialog); connect(mScriptingHtmlDialog, &QDialog::rejected, this, &Scripting::stopAllScripts); + // Only show after page loaded to allow for layouting + mScriptingHtmlDialog->connect(mScriptingHtmlDialog->webView(), &QWebEngineView::loadFinished, + mScriptingHtmlDialog, &ScriptingHtmlDialog::show); QAction *refreshAction = new QAction(QStringLiteral("refresh"), mScriptingHtmlDialog); refreshAction->setShortcut(QKeySequence::Refresh); connect(refreshAction, &QAction::triggered, this, &Scripting::refreshScript); mScriptingHtmlDialog->addAction(refreshAction); QAction *zoomInAction = KStandardAction::zoomIn(this, SLOT(zoomIn()), mScriptingHtmlDialog); mScriptingHtmlDialog->addAction(zoomInAction); QAction *zoomOutAction = KStandardAction::zoomOut(this, SLOT(zoomOut()), mScriptingHtmlDialog); mScriptingHtmlDialog->addAction(zoomOutAction); } - //Make the process information available to the script - mScriptingHtmlDialog->webView()->load(fileName); - mScriptingHtmlDialog->show(); - connect(mScriptingHtmlDialog->webView()->page()->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, this, &Scripting::setupJavascriptObjects); + // Make the process information available to the script + QWebEngineProfile *profile = mScriptingHtmlDialog->webView()->page()->profile(); + QFile webChannelJsFile(QStringLiteral(":/qtwebchannel/qwebchannel.js")); + webChannelJsFile.open(QIODevice::ReadOnly); + QString webChannelJs = QString::fromUtf8(webChannelJsFile.readAll()); + + /* Warning: Awful hack ahead! + * WebChannel does not allow synchonous calls so we need to make + * asynchronous calls synchronous. + * The conversion is achieved by caching the result of all readFile + * and fileExists calls and restarting the script on every result until + * all requests can be fulfilled synchronously. + * Another challenge is that WebEngine does not support reading + * files from /proc over file:// (they are always empty) so we need + * to keep using the ProcessObject helper methods. + */ + webChannelJs.append(QStringLiteral(R"JS( +new QWebChannel(window.qt.webChannelTransport, function(channel) { + window.process = channel.objects.process; + window.process.realReadFile = window.process.readFile; + window.process.realFileExists = window.process.fileExists; + var files = {}; // Map of all read files. null means does not exist + window.process.fileExists = function(name, cb) { + if(cb) return window.process.realFileExists(name, cb); + if (files[name] === null) + return false; // Definitely does not exist + if (typeof(files[name]) == 'string') + return true; // Definitely exists + + window.process.realFileExists(name, function(r) { + if(!r) { + files[name] = null; + refresh(); + return; + } + window.process.realReadFile(name, function(r) { + files[name] = r; + refresh(); + }); + }); + + return true; // Might exist + }; + window.process.readFile = function(name,cb) { + if(cb) return window.process.realReadFile(name, cb); + if (typeof(files[name]) == 'string') + return files[name]; // From cache + + window.process.fileExists(name); // Fill the cache + return ''; + }; + refresh && refresh(); +});)JS")); + + QWebEngineScript webChannelScript; + webChannelScript.setSourceCode(webChannelJs); + webChannelScript.setName(QStringLiteral("qwebchannel.js")); + webChannelScript.setWorldId(QWebEngineScript::MainWorld); + webChannelScript.setInjectionPoint(QWebEngineScript::DocumentCreation); + webChannelScript.setRunsOnSubFrames(false); + + profile->scripts()->insert(webChannelScript); + + // Inject a style sheet that follows system colors, otherwise we might end up with black text on dark gray background + const QString styleSheet = QStringLiteral( + "body { background: %1; color: %2; }" \ + "a { color: %3; }" \ + "a:visited { color: %4; } " + ).arg(palette().background().color().name(), + palette().text().color().name(), + palette().link().color().name(), + palette().linkVisited().color().name()); + + QString styleSheetJs = QStringLiteral("\nvar node = document.createElement('style');" + "node.innerHTML = '%1';" + "document.body.appendChild(node);").arg(styleSheet); + + QWebEngineScript styleSheetScript; + styleSheetScript.setSourceCode(styleSheetJs); + styleSheetScript.setName(QStringLiteral("stylesheet.js")); + styleSheetScript.setWorldId(QWebEngineScript::MainWorld); + styleSheetScript.setInjectionPoint(QWebEngineScript::DocumentReady); + styleSheetScript.setRunsOnSubFrames(false); + + profile->scripts()->insert(styleSheetScript); + setupJavascriptObjects(); + + mScriptingHtmlDialog->webView()->load(fileName); #else - QMessageBox::critical(this, i18n("QtWebKitWidgets not available"), - i18n("KSysGuard library was compiled without QtWebKitWidgets, please contact your distribution.")); + QMessageBox::critical(this, i18n("QtWebEngineWidgets not available"), + i18n("KSysGuard library was compiled without QtWebEngineWidgets, please contact your distribution.")); #endif } -#if HAVE_QTWEBKITWIDGETS +#if HAVE_QTWEBENGINEWIDGETS void Scripting::zoomIn() { - QWebView *webView = mScriptingHtmlDialog->webView(); + QWebEngineView *webView = mScriptingHtmlDialog->webView(); webView->setZoomFactor( webView->zoomFactor() * 1.1 ); } void Scripting::zoomOut() { - QWebView *webView = mScriptingHtmlDialog->webView(); + QWebEngineView *webView = mScriptingHtmlDialog->webView(); if(webView->zoomFactor() > 0.1) //Prevent it getting too small webView->setZoomFactor( webView->zoomFactor() / 1.1 ); } void Scripting::refreshScript() { //Call any refresh function, if it exists mProcessList->processModel()->update(0, KSysGuard::Processes::XMemory); - if(mScriptingHtmlDialog && mScriptingHtmlDialog->webView() && mScriptingHtmlDialog->webView()->page() && mScriptingHtmlDialog->webView()->page()->mainFrame()) { - mScriptingHtmlDialog->webView()->page()->mainFrame()->evaluateJavaScript(QStringLiteral("refresh();")); + mProcessObject->anythingChanged(); + if(mScriptingHtmlDialog && mScriptingHtmlDialog->webView() && mScriptingHtmlDialog->webView()->page()) { + mScriptingHtmlDialog->webView()->page()->runJavaScript(QStringLiteral("refresh && refresh();")); } } void Scripting::setupJavascriptObjects() { mProcessList->processModel()->update(0, KSysGuard::Processes::XMemory); mProcessObject = new ProcessObject(mProcessList->processModel(), mPid); - mScriptingHtmlDialog->webView()->page()->mainFrame()->addToJavaScriptWindowObject(QStringLiteral("process"), mProcessObject, QWebFrame::ScriptOwnership); + mWebChannel->registerObject(QStringLiteral("process"), mProcessObject); + mScriptingHtmlDialog->webView()->page()->setWebChannel(mWebChannel); } #endif void Scripting::stopAllScripts() { if (mScriptingHtmlDialog) mScriptingHtmlDialog->deleteLater(); mScriptingHtmlDialog = nullptr; mProcessObject = nullptr; mScriptPath.clear(); mScriptName.clear(); } void Scripting::loadContextMenu() { //Clear any existing actions qDeleteAll(mActions); mActions.clear(); QStringList scripts; const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("ksysguard/scripts/"), QStandardPaths::LocateDirectory); Q_FOREACH (const QString& dir, dirs) { QDirIterator it(dir, QStringList() << QStringLiteral("*.desktop"), QDir::NoFilter, QDirIterator::Subdirectories); while (it.hasNext()) { scripts.append(it.next()); } } foreach(const QString &script, scripts) { KDesktopFile desktopFile(script); if(!desktopFile.name().isEmpty() && !desktopFile.noDisplay()) { QAction *action = new QAction(desktopFile.readName(), this); action->setToolTip(desktopFile.readComment()); action->setIcon(QIcon(desktopFile.readIcon())); QString scriptPath = script; scriptPath.truncate(scriptPath.lastIndexOf(QLatin1Char('/'))); action->setProperty("scriptPath", QString(scriptPath + QLatin1Char('/'))); connect(action, &QAction::triggered, this, &Scripting::runScriptSlot); mProcessList->addAction(action); mActions << action; } } } void Scripting::runScriptSlot() { QAction *action = static_cast(sender()); //All the files for the script should be in the scriptPath QString path = action->property("scriptPath").toString(); QList selectedProcesses = mProcessList->selectedProcesses(); if(selectedProcesses.isEmpty()) return; mPid = selectedProcesses[0]->pid(); runScript(path, action->text()); } diff --git a/processui/scripting.h b/processui/scripting.h index 33eb3de..e9794da 100644 --- a/processui/scripting.h +++ b/processui/scripting.h @@ -1,149 +1,158 @@ /* KSysGuard, the KDE System Guard Copyright (c) 2009 John Tapsell This library 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 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KSYSGUARDSCRIPTING_H #define KSYSGUARDSCRIPTING_H #include #include #include #include #include "ProcessModel.h" #include "../config-ksysguard.h" class QAction; class ScriptingHtmlDialog; //Defined in scripting.cpp file class KSysGuardProcessList; class ProcessObject; +class QWebChannel; class Scripting : public QWidget { Q_OBJECT public: /** Create a scripting object */ Scripting(KSysGuardProcessList *parent); /** Run the script in the given path */ void runScript(const QString &path, const QString &name); /** Read all the script .desktop files and create an action for each one */ void loadContextMenu(); /** List of context menu actions that are created by loadContextMenu() */ QList actions() { return mActions; } /** Create a ScriptingHtmlDialog, if one does not already exist, and display the given html */ void displayHtml(const QString &html); public Q_SLOTS: /** Stop all scripts and delete the script engine */ void stopAllScripts(); private Q_SLOTS: /** Run the script associated with the QAction that called this slot */ void runScriptSlot(); -#if HAVE_QTWEBKITWIDGETS +#if HAVE_QTWEBENGINEWIDGETS void setupJavascriptObjects(); void refreshScript(); void zoomIn(); void zoomOut(); #endif private: /** This is created on the fly as needed, and deleted when no longer used */ ScriptingHtmlDialog *mScriptingHtmlDialog; + /** Used to expose mProcessObject to the WebEnginePage */ + QWebChannel *mWebChannel; /** The parent process list to script for */ KSysGuardProcessList * const mProcessList; /** List of context menu actions that are created by loadContextMenu() */ QList mActions; QString mScriptPath; QString mScriptName; ProcessObject *mProcessObject; qlonglong mPid; }; +// QWebChannel only reloads properties on demand, so we need a signal. +#define P_PROPERTY(x) Q_PROPERTY(x NOTIFY anythingChanged) #define PROPERTY(Type,Name) Type Name() const { KSysGuard::Process *process = mModel->getProcess(mPid); if(process) return process->Name(); else return Type();} class ProcessObject : public QObject { Q_OBJECT public: - Q_PROPERTY(qlonglong pid READ pid WRITE setPid) /* Add functionality to 'set' the pid to change which process to read from */ - Q_PROPERTY(qlonglong ppid READ parentPid) /* Map 'ppid' to 'parentPid' to give it a nicer scripting name */ - Q_PROPERTY(QString name READ name) /* Defined below to return the first word of the name */ - Q_PROPERTY(QString fullname READ fullname) /* Defined below to return 'name' */ - Q_PROPERTY(qlonglong rss READ vmRSS) /* Map 'rss' to 'vmRSS' just to give it a nicer scripting name */ - Q_PROPERTY(qlonglong urss READ vmURSS) /* Map 'urss' to 'vmURSS' just to give it a nicer scripting name */ - Q_PROPERTY(int numThreads READ numThreads) PROPERTY(int, numThreads) - Q_PROPERTY(qlonglong fsgid READ fsgid) PROPERTY(qlonglong, fsgid) - Q_PROPERTY(qlonglong parentPid READ parentPid) PROPERTY(qlonglong, parentPid) - Q_PROPERTY(QString login READ login) PROPERTY(QString, login) - Q_PROPERTY(qlonglong uid READ uid) PROPERTY(qlonglong, uid) - Q_PROPERTY(qlonglong euid READ euid) PROPERTY(qlonglong, euid) - Q_PROPERTY(qlonglong suid READ suid) PROPERTY(qlonglong, suid) - Q_PROPERTY(qlonglong fsuid READ fsuid) PROPERTY(qlonglong, fsuid) - Q_PROPERTY(qlonglong gid READ gid) PROPERTY(qlonglong, gid) - Q_PROPERTY(qlonglong egid READ egid) PROPERTY(qlonglong, egid) - Q_PROPERTY(qlonglong sgid READ sgid) PROPERTY(qlonglong, sgid) - Q_PROPERTY(qlonglong tracerpid READ tracerpid) PROPERTY(qlonglong, tracerpid) - Q_PROPERTY(QByteArray tty READ tty) PROPERTY(QByteArray, tty) - Q_PROPERTY(qlonglong userTime READ userTime) PROPERTY(qlonglong, userTime) - Q_PROPERTY(qlonglong sysTime READ sysTime) PROPERTY(qlonglong, sysTime) - Q_PROPERTY(int userUsage READ userUsage) PROPERTY(int, userUsage) - Q_PROPERTY(int sysUsage READ sysUsage) PROPERTY(int, sysUsage) - Q_PROPERTY(int totalUserUsage READ totalUserUsage) PROPERTY(int, totalUserUsage) - Q_PROPERTY(int totalSysUsage READ totalSysUsage) PROPERTY(int, totalSysUsage) - Q_PROPERTY(int numChildren READ numChildren) PROPERTY(int, numChildren) - Q_PROPERTY(int niceLevel READ niceLevel) PROPERTY(int, niceLevel) - Q_PROPERTY(int scheduler READ scheduler) PROPERTY(int, scheduler) - Q_PROPERTY(int ioPriorityClass READ ioPriorityClass) PROPERTY(int, ioPriorityClass) - Q_PROPERTY(int ioniceLevel READ ioniceLevel) PROPERTY(int, ioniceLevel) - Q_PROPERTY(qlonglong vmSize READ vmSize) PROPERTY(qlonglong, vmSize) - Q_PROPERTY(qlonglong vmRSS READ vmRSS) PROPERTY(qlonglong, vmRSS) - Q_PROPERTY(qlonglong vmURSS READ vmURSS) PROPERTY(qlonglong, vmURSS) - Q_PROPERTY(qlonglong pixmapBytes READ pixmapBytes) PROPERTY(qlonglong, pixmapBytes) - Q_PROPERTY(bool hasManagedGuiWindow READ hasManagedGuiWindow) PROPERTY(bool, hasManagedGuiWindow) - Q_PROPERTY(QString command READ command) PROPERTY(QString, command) - Q_PROPERTY(qlonglong status READ status) PROPERTY(qlonglong, status) - Q_PROPERTY(qlonglong ioCharactersRead READ ioCharactersRead) PROPERTY(qlonglong, ioCharactersRead) - Q_PROPERTY(qlonglong ioCharactersWritten READ ioCharactersWritten) PROPERTY(qlonglong, ioCharactersWritten) - Q_PROPERTY(qlonglong ioReadSyscalls READ ioReadSyscalls) PROPERTY(qlonglong, ioReadSyscalls) - Q_PROPERTY(qlonglong ioWriteSyscalls READ ioWriteSyscalls) PROPERTY(qlonglong, ioWriteSyscalls) - Q_PROPERTY(qlonglong ioCharactersActuallyRead READ ioCharactersActuallyRead) PROPERTY(qlonglong, ioCharactersActuallyRead) - Q_PROPERTY(qlonglong ioCharactersActuallyWritten READ ioCharactersActuallyWritten) PROPERTY(qlonglong, ioCharactersActuallyWritten) - Q_PROPERTY(qlonglong ioCharactersReadRate READ ioCharactersReadRate) PROPERTY(qlonglong, ioCharactersReadRate) - Q_PROPERTY(qlonglong ioCharactersWrittenRate READ ioCharactersWrittenRate) PROPERTY(qlonglong, ioCharactersWrittenRate) - Q_PROPERTY(qlonglong ioReadSyscallsRate READ ioReadSyscallsRate) PROPERTY(qlonglong, ioReadSyscallsRate) - Q_PROPERTY(qlonglong ioWriteSyscallsRate READ ioWriteSyscallsRate) PROPERTY(qlonglong, ioWriteSyscallsRate) - Q_PROPERTY(qlonglong ioCharactersActuallyReadRate READ ioCharactersActuallyReadRate) PROPERTY(qlonglong, ioCharactersActuallyReadRate) - Q_PROPERTY(qlonglong ioCharactersActuallyWrittenRate READ ioCharactersActuallyWrittenRate) PROPERTY(qlonglong, ioCharactersActuallyWrittenRate) + P_PROPERTY(qlonglong pid READ pid WRITE setPid) /* Add functionality to 'set' the pid to change which process to read from */ + P_PROPERTY(qlonglong ppid READ parentPid) /* Map 'ppid' to 'parentPid' to give it a nicer scripting name */ + P_PROPERTY(QString name READ name) /* Defined below to return the first word of the name */ + P_PROPERTY(QString fullname READ fullname) /* Defined below to return 'name' */ + P_PROPERTY(qlonglong rss READ vmRSS) /* Map 'rss' to 'vmRSS' just to give it a nicer scripting name */ + P_PROPERTY(qlonglong urss READ vmURSS) /* Map 'urss' to 'vmURSS' just to give it a nicer scripting name */ + P_PROPERTY(int numThreads READ numThreads) PROPERTY(int, numThreads) + P_PROPERTY(qlonglong fsgid READ fsgid) PROPERTY(qlonglong, fsgid) + P_PROPERTY(qlonglong parentPid READ parentPid) PROPERTY(qlonglong, parentPid) + P_PROPERTY(QString login READ login) PROPERTY(QString, login) + P_PROPERTY(qlonglong uid READ uid) PROPERTY(qlonglong, uid) + P_PROPERTY(qlonglong euid READ euid) PROPERTY(qlonglong, euid) + P_PROPERTY(qlonglong suid READ suid) PROPERTY(qlonglong, suid) + P_PROPERTY(qlonglong fsuid READ fsuid) PROPERTY(qlonglong, fsuid) + P_PROPERTY(qlonglong gid READ gid) PROPERTY(qlonglong, gid) + P_PROPERTY(qlonglong egid READ egid) PROPERTY(qlonglong, egid) + P_PROPERTY(qlonglong sgid READ sgid) PROPERTY(qlonglong, sgid) + P_PROPERTY(qlonglong tracerpid READ tracerpid) PROPERTY(qlonglong, tracerpid) + P_PROPERTY(QByteArray tty READ tty) PROPERTY(QByteArray, tty) + P_PROPERTY(qlonglong userTime READ userTime) PROPERTY(qlonglong, userTime) + P_PROPERTY(qlonglong sysTime READ sysTime) PROPERTY(qlonglong, sysTime) + P_PROPERTY(int userUsage READ userUsage) PROPERTY(int, userUsage) + P_PROPERTY(int sysUsage READ sysUsage) PROPERTY(int, sysUsage) + P_PROPERTY(int totalUserUsage READ totalUserUsage) PROPERTY(int, totalUserUsage) + P_PROPERTY(int totalSysUsage READ totalSysUsage) PROPERTY(int, totalSysUsage) + P_PROPERTY(int numChildren READ numChildren) PROPERTY(int, numChildren) + P_PROPERTY(int niceLevel READ niceLevel) PROPERTY(int, niceLevel) + P_PROPERTY(int scheduler READ scheduler) PROPERTY(int, scheduler) + P_PROPERTY(int ioPriorityClass READ ioPriorityClass) PROPERTY(int, ioPriorityClass) + P_PROPERTY(int ioniceLevel READ ioniceLevel) PROPERTY(int, ioniceLevel) + P_PROPERTY(qlonglong vmSize READ vmSize) PROPERTY(qlonglong, vmSize) + P_PROPERTY(qlonglong vmRSS READ vmRSS) PROPERTY(qlonglong, vmRSS) + P_PROPERTY(qlonglong vmURSS READ vmURSS) PROPERTY(qlonglong, vmURSS) + P_PROPERTY(qlonglong pixmapBytes READ pixmapBytes) PROPERTY(qlonglong, pixmapBytes) + P_PROPERTY(bool hasManagedGuiWindow READ hasManagedGuiWindow) PROPERTY(bool, hasManagedGuiWindow) + P_PROPERTY(QString command READ command) PROPERTY(QString, command) + P_PROPERTY(qlonglong status READ status) PROPERTY(qlonglong, status) + P_PROPERTY(qlonglong ioCharactersRead READ ioCharactersRead) PROPERTY(qlonglong, ioCharactersRead) + P_PROPERTY(qlonglong ioCharactersWritten READ ioCharactersWritten) PROPERTY(qlonglong, ioCharactersWritten) + P_PROPERTY(qlonglong ioReadSyscalls READ ioReadSyscalls) PROPERTY(qlonglong, ioReadSyscalls) + P_PROPERTY(qlonglong ioWriteSyscalls READ ioWriteSyscalls) PROPERTY(qlonglong, ioWriteSyscalls) + P_PROPERTY(qlonglong ioCharactersActuallyRead READ ioCharactersActuallyRead) PROPERTY(qlonglong, ioCharactersActuallyRead) + P_PROPERTY(qlonglong ioCharactersActuallyWritten READ ioCharactersActuallyWritten) PROPERTY(qlonglong, ioCharactersActuallyWritten) + P_PROPERTY(qlonglong ioCharactersReadRate READ ioCharactersReadRate) PROPERTY(qlonglong, ioCharactersReadRate) + P_PROPERTY(qlonglong ioCharactersWrittenRate READ ioCharactersWrittenRate) PROPERTY(qlonglong, ioCharactersWrittenRate) + P_PROPERTY(qlonglong ioReadSyscallsRate READ ioReadSyscallsRate) PROPERTY(qlonglong, ioReadSyscallsRate) + P_PROPERTY(qlonglong ioWriteSyscallsRate READ ioWriteSyscallsRate) PROPERTY(qlonglong, ioWriteSyscallsRate) + P_PROPERTY(qlonglong ioCharactersActuallyReadRate READ ioCharactersActuallyReadRate) PROPERTY(qlonglong, ioCharactersActuallyReadRate) + P_PROPERTY(qlonglong ioCharactersActuallyWrittenRate READ ioCharactersActuallyWrittenRate) PROPERTY(qlonglong, ioCharactersActuallyWrittenRate) ProcessObject(ProcessModel * processModel, int pid); void update(KSysGuard::Process *process); int pid() const { return mPid; } void setPid(int pid) { mPid = pid; } QString name() const { KSysGuard::Process *process = mModel->getProcess(mPid); if(process) return process->name().section(QLatin1Char(' '), 0,0); else return QString(); } QString fullname() const { KSysGuard::Process *process = mModel->getProcess(mPid); if(process) return process->name(); else return QString(); } public Q_SLOTS: bool fileExists(const QString &filename); QString readFile(const QString &filename); + + Q_SIGNALS: + void anythingChanged(); + private: int mPid; ProcessModel *mModel; }; #endif