diff --git a/startkde/CMakeLists.txt b/startkde/CMakeLists.txt index 494680fe9..e360bb23f 100644 --- a/startkde/CMakeLists.txt +++ b/startkde/CMakeLists.txt @@ -1,33 +1,32 @@ add_subdirectory(kcminit) -add_subdirectory(kstartupconfig) add_subdirectory(ksyncdbusenv) add_subdirectory(waitforname) qt5_add_dbus_interface( startplasma_SRCS ${CMAKE_SOURCE_DIR}/ksplash/ksplashqml/org.kde.KSplash.xml ksplashinterface ) -add_executable(startplasma-x11 startplasma.cpp startplasma-x11.cpp kcheckrunning/kcheckrunning.cpp kstartupconfig/kstartupconfig.cpp ${startplasma_SRCS}) -add_executable(startplasma-wayland startplasma.cpp startplasma-wayland.cpp kstartupconfig/kstartupconfig.cpp ${startplasma_SRCS}) -add_executable(startplasma-waylandsession startplasma.cpp startplasma-waylandsession.cpp kstartupconfig/kstartupconfig.cpp ${startplasma_SRCS}) +add_executable(startplasma-x11 startplasma.cpp startplasma-x11.cpp kcheckrunning/kcheckrunning.cpp ${startplasma_SRCS}) +add_executable(startplasma-wayland startplasma.cpp startplasma-wayland.cpp ${startplasma_SRCS}) +add_executable(startplasma-waylandsession startplasma.cpp startplasma-waylandsession.cpp ${startplasma_SRCS}) target_link_libraries(startplasma-x11 PRIVATE Qt5::Core Qt5::DBus KF5::ConfigCore X11::X11 # for kcheckrunning ) target_link_libraries(startplasma-wayland PRIVATE Qt5::Core Qt5::DBus KF5::ConfigCore) target_link_libraries(startplasma-waylandsession PRIVATE Qt5::Core Qt5::DBus KF5::ConfigCore) #FIXME: reconsider, looks fishy if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr") set_property(SOURCE startplasma.cpp APPEND PROPERTY COMPILE_DEFINITIONS XCURSOR_PATH="${KDE_INSTALL_FULL_DATAROOTDIR}/icons:$XCURSOR_PATH:~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons") endif() configure_file(config-startplasma.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-startplasma.h) install(TARGETS startplasma-x11 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS startplasma-wayland ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(TARGETS startplasma-waylandsession DESTINATION ${KDE_INSTALL_LIBEXECDIR}) install(PROGRAMS plasma-sourceenv.sh DESTINATION ${KDE_INSTALL_LIBEXECDIR}) diff --git a/startkde/kstartupconfig/CMakeLists.txt b/startkde/kstartupconfig/CMakeLists.txt deleted file mode 100644 index b8f52f873..000000000 --- a/startkde/kstartupconfig/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ - -# TODO: merge into kstartupconfig5 -add_executable(kdostartupconfig5 kdostartupconfig.cpp) - -target_link_libraries(kdostartupconfig5 - Qt5::Core - KF5::ConfigCore - KF5::CoreAddons - ${LIBBSD_LIBRARIES}) - -install(TARGETS kdostartupconfig5 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) - diff --git a/startkde/kstartupconfig/kdostartupconfig.cpp b/startkde/kstartupconfig/kdostartupconfig.cpp deleted file mode 100644 index 0e6f09e09..000000000 --- a/startkde/kstartupconfig/kdostartupconfig.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************************** - - Copyright (C) 2005 Lubos Lunak - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -****************************************************************************/ - -#undef QT_NO_CAST_ASCII - -// See description in kstartupconfig.cpp . -#include -#include -#include -#include - -#include -#include -#include - -static QString get_entry( QString* ll ) - { - QString& l = *ll; - l = l.trimmed(); - if( l.isEmpty()) - return QString(); - QString ret; - if( l[ 0 ] == '\'' ) - { - int pos = 1; - while( pos < l.length() && l[ pos ] != '\'' ) - ret += l[ pos++ ]; - if( pos >= l.length()) - { - *ll = QString(); - return QString(); - } - *ll = l.mid( pos + 1 ); - return ret; - } - int pos = 0; - while( pos < l.length() && l[ pos ] != ' ' ) - ret += l[ pos++ ]; - *ll = l.mid( pos ); - return ret; - } - -int main( int argc, char **argv ) - { - Q_UNUSED(argc); - Q_UNUSED(argv); - QString path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); - QDir().mkdir(path); - - QString keysname = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, QStringLiteral("startupconfigkeys")); - QFile keys( keysname ); - if( !keys.open( QIODevice::ReadOnly )) - return 3; - QFile f1(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/startupconfig")); - if( !f1.open( QIODevice::WriteOnly )) - return 4; - QFile f2(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/startupconfigfiles")); - if( !f2.open( QIODevice::WriteOnly )) - return 5; - QTextStream startupconfig( &f1 ); - QTextStream startupconfigfiles( &f2 ); - startupconfig << "#! /bin/sh\n"; - for(;;) - { - QString line = QString::fromLocal8Bit(keys.readLine()).trimmed(); - if( line.isEmpty()) - break; - - QString tmp = line; - QString file, group, key, def; - file = get_entry( &tmp ); - group = get_entry( &tmp ); - key = get_entry( &tmp ); - def = get_entry( &tmp ); - if( file.isEmpty() || group.isEmpty()) - return 6; - if( group.startsWith( '[' ) && group.endsWith( ']' ) ) - { // whole config group - KConfig cfg( file ); - group = group.mid( 1, group.length() - 2 ); - KConfigGroup cg(&cfg, group); - QMap< QString, QString > entries = cg.entryMap( ); - startupconfig << "# " << line << "\n"; - for( QMap< QString, QString >::ConstIterator it = entries.constBegin(); - it != entries.constEnd(); - ++it ) - { - QString key = it.key(); - QString value = *it; - startupconfig << "export " << file.replace( ' ', '_' ).toLower() - << "_" << group.replace( ' ', '_' ).toLower() - << "_" << key.replace( ' ', '_' ).toLower() - << "=" << KShell::quoteArg( value ) << "\n"; - } - } - else - { // a single key - if( key.isEmpty()) - return 7; - KConfig cfg( file ); - KConfigGroup cg(&cfg, group ); - QString value = cg.readEntry( key, def ); - startupconfig << "# " << line << "\n"; - startupconfig << "export " << file.replace( ' ', '_' ).toLower() - << "_" << group.replace( ' ', '_' ).toLower() - << "_" << key.replace( ' ', '_' ).toLower() - << "=" << KShell::quoteArg( value ) << "\n"; - } - startupconfigfiles << line << endl; - - //we want a list of ~/.config + /usr/share/config (on a normal setup). - //These files may not exist yet as the latter is used by kconf_update - QStringList configDirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation); - foreach (const QString &location, QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation)) { - //some people accidentally have empty prefixes in their XDG_DATA_DIRS, strip those out - if (location.isEmpty()) { - continue; - } - configDirs << (location + "/config"); - } - - foreach (const QString &configDir, configDirs) { - const QString cfg = configDir + '/' + file; - if (QFile::exists(cfg)) - startupconfigfiles << cfg << "\n"; - else - startupconfigfiles << "!" << cfg << "\n"; - } - - startupconfigfiles << "*\n"; - } - - return 0; -} diff --git a/startkde/kstartupconfig/kstartupconfig.cpp b/startkde/kstartupconfig/kstartupconfig.cpp deleted file mode 100644 index 5691829a2..000000000 --- a/startkde/kstartupconfig/kstartupconfig.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** - - Copyright (C) 2005 Lubos Lunak - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -****************************************************************************/ - -/* - -This utility helps to have some configuration options available in startkde -without the need to launch anything linked to KDE libraries (which may need -some time to load). - -The configuration options are written to $KDEHOME/share/config/startupconfigkeys, -one option per line, as . It is possible to -use ' for quoting multiword entries. Values of these options will be written -to $KDEHOME/share/config/startupconfig as a shell script that will set -the values to shell variables, named __ (all spaces replaced -by underscores, everything lowercase). So e.g. line -"ksplashrc KSplash Theme Default" may result in "ksplashrc_ksplash_theme=Default". - -In order to real a whole group it is possible to use <[group]>, e.g. -"ksplashrc [KSplash]", which will set shell variables for all keys in the group. -It is not possible to specify default values, but since the configuration options -are processed in the order they are specified this can be solved by first -specifying a group and then all the entries that need default values. - -When a kconf_update script is used to update such option, kstartupconfig is run -before kconf_update and therefore cannot see the change in time. To avoid this -problem, together with the kconf_update script also the matching global config -file should be updated (any change, kstartupconfig will see the timestamp change). - -Note that the kdeglobals config file is not used as a depedendency for other config -files. - -Since the checking is timestamp-based, config files that are frequently updated -should not be used. - -Kstartupconfig works by storing every line from startupconfigkeys in file startupconfigfiles -followed by paths of all files that are relevant to the option. Non-existent files -have '!' prepended (for the case they'll be later created), the list of files is -terminated by line containing '*'. If the timestamps of all relevant files are older -than the timestamp of the startupconfigfile file, there's no need to update anything. -Otherwise kdostartupconfig is launched to create or update all the necessary files -(which already requires loading KDE libraries, but this case should be rare). - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -int kStartupConfig() -{ - time_t config_time; - FILE* config; - FILE* keys; - struct stat st; - std::string kdehome; - std::string filename; - - if (getenv( "XDG_CONFIG_HOME" )) { - kdehome = getenv("XDG_CONFIG_HOME"); - } else { - kdehome = std::string(getenv("HOME")) + "/.config"; - } - filename = kdehome + "/startupconfig"; - if (access(filename.c_str(), R_OK) != 0) - goto doit; - filename = kdehome + "/startupconfigfiles"; - if (stat(filename.c_str(), &st) != 0) - goto doit; - config_time = st.st_mtime; - config = fopen(filename.c_str(), "r"); - if( config == nullptr ) - goto doit; - filename = kdehome + "/startupconfigkeys"; - keys = fopen(filename.c_str(), "r"); - if( keys == nullptr ) - { - fclose(config); - return 2; - } - for(;;) - { - char* nl; - char keyline[ 1024 ]; - char line[ 1024 ]; - - if( fgets( keyline, 1023, keys ) == nullptr ) - return 0; - if( (nl = strchr( keyline, '\n' )) ) - *nl = '\0'; - if( fgets( line, 1023, config ) == nullptr ) - break; - if( (nl = strchr( line, '\n' )) ) - *nl = '\0'; - if( strcmp( keyline, line ) != 0 ) - break; - for(;;) - { - if( fgets( line, 1023, config ) == nullptr ) - goto doit2; - if( (nl = strchr( line, '\n' )) ) - *nl = '\0'; - if( *line == '\0' ) - goto doit2; - if( *line == '*' ) - break; - if( *line == '!' ) - { - if( access( line + 1, R_OK ) == 0 ) - goto doit2; /* file now exists -> update */ - } - else - { - if( stat( line, &st ) != 0 ) - goto doit2; - if( st.st_mtime > config_time ) - goto doit2; - } - } - } - doit2: - fclose( keys ); - fclose( config ); - doit: - return system( "kdostartupconfig5" ); - } diff --git a/startkde/kstartupconfig/kstartupconfig.h b/startkde/kstartupconfig/kstartupconfig.h deleted file mode 100644 index 269c943f5..000000000 --- a/startkde/kstartupconfig/kstartupconfig.h +++ /dev/null @@ -1,31 +0,0 @@ -/**************************************************************************** - - Copyright (C) 2019 Aleix Pol Gonzalez - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - -****************************************************************************/ - -#ifndef KSTARTUPCONFIG_H -#define KSTARTUPCONFIG_H - -/// returns 0 if successful -int kStartupConfig(); - -#endif diff --git a/startkde/startplasma-wayland.cpp b/startkde/startplasma-wayland.cpp index b7825597d..9612bd7de 100644 --- a/startkde/startplasma-wayland.cpp +++ b/startkde/startplasma-wayland.cpp @@ -1,79 +1,77 @@ /* This file is part of the KDE project Copyright (C) 2019 Aleix Pol Gonzalez 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 "startplasma.h" -#include +#include #include #include #include int main(int /*argc*/, char** /*argv*/) { - if (!createStartupConfig()) - return 1; - + createConfigDirectory(); setupCursor(true); { - KSharedConfig::Ptr fonts = KSharedConfig::openConfig("kcmfonts"); - KConfigGroup group(fonts, "General"); + KConfig fonts("kcmfonts"); + KConfigGroup group = fonts.group("General"); auto dpiSetting = group.readEntry("forceFontDPIWayland", 96); auto dpi = dpiSetting == 0 ? 96 : dpiSetting; qputenv("QT_WAYLAND_FORCE_DPI", QByteArray::number(dpi)); } // Query whether org.freedesktop.locale1 is available. If it is, try to // set XKB_DEFAULT_{MODEL,LAYOUT,VARIANT,OPTIONS} accordingly. if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.locale1")) { auto queryAndSet = [](const QByteArray &var, const QByteArray & value) { QDBusInterface iface(QStringLiteral("org.freedesktop.locale1"), QStringLiteral("/org/freedesktop/locale1"), QStringLiteral("org.freedesktop.locale1"), QDBusConnection::systemBus()); QString r = iface.property(value).toString(); if (!r.isEmpty()) qputenv(var, r.toLatin1()); }; queryAndSet("X11MODEL", "org.freedesktop.locale1.X11Model"); queryAndSet("X11LAYOUT", "org.freedesktop.locale1.X11Layout"); queryAndSet("X11VARIANT", "org.freedesktop.locale1.X11Variant"); queryAndSet("X11OPTIONS", "org.freedesktop.locale1.X11Options"); } runEnvironmentScripts(); if (!qEnvironmentVariableIsSet("DBUS_SESSION_BUS_ADDRESS")) { out << "startplasmacompositor: Could not start D-Bus. Can you call qdbus?\n"; return 1; } setupPlasmaEnvironment(); qputenv("XDG_SESSION_TYPE", "wayland"); if (!syncDBusEnvironment()) { out << "Could not sync environment to dbus.\n"; return 1; } runSync(KWIN_WAYLAND_BIN_PATH, { "--xwayland", "--libinput", "--exit-with-session=" CMAKE_INSTALL_FULL_LIBEXECDIR "/startplasma-waylandsession" }); out << "startplasmacompositor: Shutting down...\n"; cleanupPlasmaEnvironment(); out << "startplasmacompositor: Done.\n"; return 0; } diff --git a/startkde/startplasma-x11.cpp b/startkde/startplasma-x11.cpp index 8940489df..7627210d4 100644 --- a/startkde/startplasma-x11.cpp +++ b/startkde/startplasma-x11.cpp @@ -1,119 +1,120 @@ /* This file is part of the KDE project Copyright (C) 2019 Aleix Pol Gonzalez 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 "startplasma.h" #include #include -#include +#include #include void sighupHandler(int) { out << "GOT SIGHUP\n"; } int main(int /*argc*/, char** /*argv*/) { // When the X server dies we get a HUP signal from xinit. We must ignore it // because we still need to do some cleanup. signal(SIGHUP, sighupHandler); // Boot sequence: // // kdeinit is used to fork off processes which improves memory usage // and startup time. // // * kdeinit starts klauncher first. // * Then kded is started. kded is responsible for keeping the sycoca // database up to date. When an up to date database is present it goes // into the background and the startup continues. // * Then kdeinit starts kcminit. kcminit performs initialisation of // certain devices according to the user's settings // // * Then ksmserver is started which takes control of the rest of the startup sequence // Check if a Plasma session already is running and whether it's possible to connect to X switch (kCheckRunning()) { case NoX11: out << "$DISPLAY is not set or cannot connect to the X server.\n"; return 1; case PlasmaRunning: messageBox("Plasma seems to be already running on this display.\n"); return 1; case NoPlasmaRunning: break; } - if (!createStartupConfig()) - return 1; + createConfigDirectory(); runStartupConfig(); //Do not sync any of this section with the wayland versions as there scale factors are //sent properly over wl_output { - const auto screenScaleFactors = qgetenv("kdeglobals_kscreen_screenscalefactors"); + KConfig cfg("kdeglobals"); + + const auto screenScaleFactors = cfg.group("KScreen").readEntry("ScreenScaleFactors", QByteArray()); if (!screenScaleFactors.isEmpty()) { qputenv("QT_SCREEN_SCALE_FACTORS", screenScaleFactors); if (screenScaleFactors == "2" || screenScaleFactors == "3") { qputenv("GDK_SCALE", screenScaleFactors); qputenv("GDK_DPI_SCALE", QByteArray::number(1/screenScaleFactors.toInt(), 'g', 3)); } } } setupCursor(false); setupFontDpi(); QScopedPointer ksplash(setupKSplash()); runEnvironmentScripts(); out << "startkde: Starting up...\n"; setupPlasmaEnvironment(); setupX11(); if (!syncDBusEnvironment()) { // Startup error messageBox("Could not sync environment to dbus.\n"); return 1; } if (!startKDEInit()) return 1; if (!startKSMServer()) return 1; // Anything after here is logout // It is not called after shutdown/restart waitForKonqi(); out << "startkde: Shutting down...\n"; runSync("kdeinit5_shutdown", {}); cleanupPlasmaEnvironment(); cleanupX11(); out << "startkde: Done.\n"; return 0; } diff --git a/startkde/startplasma.cpp b/startkde/startplasma.cpp index b159b0d00..ea4913a16 100644 --- a/startkde/startplasma.cpp +++ b/startkde/startplasma.cpp @@ -1,417 +1,400 @@ /* This file is part of the KDE project Copyright (C) 2019 Aleix Pol Gonzalez 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 #include #include #include #include -#include +#include #include #include -#include "kstartupconfig/kstartupconfig.h" #include "startplasma.h" QTextStream out(stderr); void messageBox(const QString &text) { out << text; runSync("xmessage", {"-geometry", "500x100", text}); } QStringList allServices(const QLatin1String& prefix) { QDBusConnectionInterface *bus = QDBusConnection::sessionBus().interface(); const QStringList services = bus->registeredServiceNames(); QMap servicesWithAliases; for (const QString &serviceName : services) { QDBusReply reply = bus->serviceOwner(serviceName); QString owner = reply; if (owner.isEmpty()) owner = serviceName; servicesWithAliases[owner].append(serviceName); } QStringList names; for (auto it = servicesWithAliases.constBegin(); it != servicesWithAliases.constEnd(); ++it) { if (it.value().startsWith(prefix)) names << it.value(); } names.removeDuplicates(); names.sort(); return names; } int runSync(const QString& program, const QStringList &args, const QStringList &env) { QProcess p; if (!env.isEmpty()) p.setEnvironment(QProcess::systemEnvironment() << env); p.setProcessChannelMode(QProcess::ForwardedChannels); p.start(program, args); qDebug() << "started..." << program << args; p.waitForFinished(-1); return p.exitCode(); } void writeFile(const QString& path, const QByteArray& contents) { QFile f(path); if (!f.open(QIODevice::WriteOnly)) { out << "Could not write into " << f.fileName() <<".\n"; exit(1); } f.write(contents); } void sourceFiles(const QStringList &files) { QStringList filteredFiles; std::copy_if(files.begin(), files.end(), std::back_inserter(filteredFiles), [](const QString& i){ return QFileInfo(i).isReadable(); } ); if (filteredFiles.isEmpty()) return; filteredFiles.prepend(CMAKE_INSTALL_FULL_LIBEXECDIR "/plasma-sourceenv.sh"); QProcess p; qDebug() << "sourcing..." << filteredFiles; p.start("/bin/sh", filteredFiles); p.waitForFinished(-1); const auto fullEnv = p.readAllStandardOutput(); auto envs = fullEnv.split('\n'); for (auto &env: envs) { if (env.startsWith("_=")) continue; const int idx = env.indexOf('='); if (Q_UNLIKELY(idx <= 0)) continue; if (qgetenv(env.left(idx)) != env.mid(idx+1)) { qDebug() << "setting..." << env.left(idx) << env.mid(idx+1) << "was" << qgetenv(env.left(idx)); qputenv(env.left(idx), env.mid(idx+1)); } } } -bool createStartupConfig() +void createConfigDirectory() { const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); if (!QDir().mkpath(configDir)) out << "Could not create config directory XDG_CONFIG_HOME: " << configDir << '\n'; - - //This is basically setting defaults so we can use them with kStartupConfig() - //TODO: see into passing them as an argument - writeFile(configDir + "/startupconfigkeys", - "kcminputrc Mouse cursorTheme 'breeze_cursors'\n" - "kcminputrc Mouse cursorSize ''\n" - "ksplashrc KSplash Theme Breeze\n" - "ksplashrc KSplash Engine KSplashQML\n" - "kdeglobals KScreen ScaleFactor ''\n" - "kdeglobals KScreen ScreenScaleFactors ''\n" - "kcmfonts General forceFontDPI 0\n" - ); - - //preload the user's locale on first start - const QString localeFile = configDir + "/plasma-localerc"; - if (!QFile::exists(localeFile)) { - writeFile(localeFile, - QByteArray("[Formats]\n" - "LANG=" +qgetenv("LANG")+ "\n")); - } - - if (int code = kStartupConfig()) { - messageBox("kStartupConfig() does not exist or fails. The error code is " + QByteArray::number(code) + ". Check your installation.\n"); - return false; - } - - return true; } void runStartupConfig() { const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); //export LC_* variables set by kcmshell5 formats into environment //so it can be picked up by QLocale and friends. - sourceFiles({configDir + "/startupconfig", configDir + "/plasma-locale-settings.sh"}); + sourceFiles({configDir + "/plasma-locale-settings.sh"}); } void setupCursor(bool wayland) { - const auto kcminputrc_mouse_cursorsize = qgetenv("kcminputrc_mouse_cursorsize"); - const auto kcminputrc_mouse_cursortheme = qgetenv("kcminputrc_mouse_cursortheme"); + const KConfig cfg("ksplashrc"); + const KConfigGroup inputCfg = cfg.group("Mouse"); + + const auto kcminputrc_mouse_cursorsize = inputCfg.readEntry("cursorSize", QString()); + const auto kcminputrc_mouse_cursortheme = inputCfg.readEntry("cursorTheme", QString()); if (!kcminputrc_mouse_cursortheme.isEmpty() || !kcminputrc_mouse_cursorsize.isEmpty()) { #ifdef XCURSOR_PATH QByteArray path(XCURSOR_PATH); path.replace("$XCURSOR_PATH", qgetenv("XCURSOR_PATH")); qputenv("XCURSOR_PATH", path); #endif } //TODO: consider linking directly const int applyMouseStatus = wayland ? 0 : runSync("kapplymousetheme", { "kcminputrc_mouse_cursortheme", "kcminputrc_mouse_cursorsize" }); if (applyMouseStatus == 10) { qputenv("XCURSOR_THEME", "breeze_cursors"); } else if (!kcminputrc_mouse_cursortheme.isEmpty()) { - qputenv("XCURSOR_THEME", kcminputrc_mouse_cursortheme); + qputenv("XCURSOR_THEME", kcminputrc_mouse_cursortheme.toUtf8()); } if (!kcminputrc_mouse_cursorsize.isEmpty()) { - qputenv("XCURSOR_SIZE", kcminputrc_mouse_cursorsize); + qputenv("XCURSOR_SIZE", kcminputrc_mouse_cursorsize.toUtf8()); } } // Source scripts found in /plasma-workspace/env/*.sh // (where correspond to the system and user's configuration // directory. // // This is where you can define environment variables that will be available to // all KDE programs, so this is where you can run agents using e.g. eval `ssh-agent` // or eval `gpg-agent --daemon`. // Note: if you do that, you should also put "ssh-agent -k" as a shutdown script // // (see end of this file). // For anything else (that doesn't set env vars, or that needs a window manager), // better use the Autostart folder. void runEnvironmentScripts() { QStringList scripts; const auto locations = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("plasma-workspace/env"), QStandardPaths::LocateDirectory); for (const QString & location : locations) { QDir dir(location); const auto dirScripts = dir.entryInfoList({QStringLiteral("*.sh")}); for (const auto script : dirScripts) { scripts << script.absoluteFilePath(); } } sourceFiles(scripts); // Make sure that the KDE prefix is first in XDG_DATA_DIRS and that it's set at all. // The spec allows XDG_DATA_DIRS to be not set, but X session startup scripts tend // to set it to a list of paths *not* including the KDE prefix if it's not /usr or // /usr/local. if (!qEnvironmentVariableIsSet("XDG_DATA_DIRS")) { qputenv("XDG_DATA_DIRS", KDE_INSTALL_FULL_DATAROOTDIR ":/usr/share:/usr/local/share"); } } // Mark that full KDE session is running (e.g. Konqueror preloading works only // with full KDE running). The KDE_FULL_SESSION property can be detected by // any X client connected to the same X session, even if not launched // directly from the KDE session but e.g. using "ssh -X", kdesu. $KDE_FULL_SESSION // however guarantees that the application is launched in the same environment // like the KDE session and that e.g. KDE utilities/libraries are available. // KDE_FULL_SESSION property is also only available since KDE 3.5.5. // The matching tests are: // For $KDE_FULL_SESSION: // if test -n "$KDE_FULL_SESSION"; then ... whatever // For KDE_FULL_SESSION property (on X11): // xprop -root | grep "^KDE_FULL_SESSION" >/dev/null 2>/dev/null // if test $? -eq 0; then ... whatever // // Additionally there is $KDE_SESSION_UID with the uid // of the user running the KDE session. It should be rarely needed (e.g. // after sudo to prevent desktop-wide functionality in the new user's kded). // // Since KDE4 there is also KDE_SESSION_VERSION, containing the major version number. // void setupPlasmaEnvironment() { //Manually disable auto scaling because we are scaling above //otherwise apps that manually opt in for high DPI get auto scaled by the developer AND manually scaled by us qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "0"); qputenv("KDE_FULL_SESSION", "true"); qputenv("KDE_SESSION_VERSION", "5"); qputenv("KDE_SESSION_UID", QByteArray::number(getuid())); qputenv("XDG_CURRENT_DESKTOP", "KDE"); } void setupX11() { // Set a left cursor instead of the standard X11 "X" cursor, since I've heard // from some users that they're confused and don't know what to do. This is // especially necessary on slow machines, where starting KDE takes one or two // minutes until anything appears on the screen. // // If the user has overwritten fonts, the cursor font may be different now // so don't move this up. runSync("xsetroot", {"-cursor_name", "left_ptr"}); runSync("xprop", {"-root", "-f", "KDE_FULL_SESSION", "8t", "-set", "KDE_FULL_SESSION", "true"}); runSync("xprop", {"-root", "-f", "KDE_SESSION_VERSION", "32c", "-set", "KDE_SESSION_VERSION", "5"}); } void cleanupX11() { runSync("xprop", { "-root", "-remove", "KDE_FULL_SESSION" }); runSync("xprop", { "-root", "-remove", "KDE_SESSION_VERSION" }); } // TODO: Check if Necessary void cleanupPlasmaEnvironment() { qunsetenv("KDE_FULL_SESSION"); qunsetenv("KDE_SESSION_VERSION"); qunsetenv("KDE_SESSION_UID"); } // kwin_wayland can possibly also start dbus-activated services which need env variables. // In that case, the update in startplasma might be too late. bool syncDBusEnvironment() { int exitCode; // At this point all environment variables are set, let's send it to the DBus session server to update the activation environment if (!QStandardPaths::findExecutable("dbus-update-activation-environment").isEmpty()) exitCode = runSync("dbus-update-activation-environment", { "--systemd", "--all" }); else exitCode = runSync(CMAKE_INSTALL_FULL_LIBEXECDIR "/ksyncdbusenv", {}); return exitCode == 0; } void setupFontDpi() { - const auto kcmfonts_general_forcefontdpi = qgetenv("kcmfonts_general_forcefontdpi"); - if (kcmfonts_general_forcefontdpi == "0") { + KConfig cfg("kcmfonts"); + KConfigGroup fontsCfg(&cfg, "General"); + + if (!fontsCfg.readEntry("forceFontDPI", false)) { return; } //TODO port to c++? const QByteArray input = "Xft.dpi: kcmfonts_general_forcefontdpi"; QProcess p; p.start("xrdb", { "-quiet", "-merge", "-nocpp" }); p.setProcessChannelMode(QProcess::ForwardedChannels); p.write(input); p.closeWriteChannel(); p.waitForFinished(-1); } static bool dl = false; QProcess* setupKSplash() { const auto dlstr = qgetenv("DESKTOP_LOCKED"); dl = dlstr == "true" || dlstr == "1"; qunsetenv("DESKTOP_LOCKED"); // Don't want it in the environment QProcess* p = nullptr; if (!dl) { - const auto ksplashrc_ksplash_engine = qgetenv("ksplashrc_ksplash_engine"); + const KConfig cfg("ksplashrc"); // the splashscreen and progress indicator - if (ksplashrc_ksplash_engine == "KSplashQML") { + KConfigGroup ksplashCfg = cfg.group("KSplash"); + if (ksplashCfg.readEntry("Engine") == QLatin1String("KSplashQML")) { p = new QProcess; - p->start("ksplashqml", {QString::fromUtf8(qgetenv("ksplashrc_ksplash_theme"))}); + p->start("ksplashqml", { ksplashCfg.readEntry("Theme") }); } } return p; } void setupGSLib() // Get Ghostscript to look into user's KDE fonts dir for additional Fontmap { const QByteArray usr_fdir = QFile::encodeName(QDir::home().absoluteFilePath(".fonts")); if (qEnvironmentVariableIsSet("GS_LIB")) { qputenv("GS_LIB", usr_fdir + ':' + qgetenv("GS_LIB")); } else { qputenv("GS_LIB", usr_fdir); } } bool startKDEInit() { // We set LD_BIND_NOW to increase the efficiency of kdeinit. // kdeinit unsets this variable before loading applications. const int exitCode = runSync(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/start_kdeinit_wrapper", { "--kded", "+kcminit_startup" }, { "LD_BIND_NOW=true" }); if (exitCode != 0) { messageBox("startkde: Could not start kdeinit5. Check your installation."); return false; } OrgKdeKSplashInterface iface("org.kde.KSplash", "/KSplash", QDBusConnection::sessionBus()); - iface.setStage("kinit"); + auto reply = iface.setStage("kinit"); + auto watcher = new QDBusPendingCallWatcher(reply); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [] (QDBusPendingCallWatcher* watcher) { + watcher->deleteLater(); + qDebug() << "ksplash reply arrived" << watcher->error(); + }); return true; } bool startKSMServer() { // finally, give the session control to the session manager // see kdebase/ksmserver for the description of the rest of the startup sequence // if the KDEWM environment variable has been set, then it will be used as KDE's // window manager instead of kwin. // if KDEWM is not set, ksmserver will ensure kwin is started. // kwrapper5 is used to reduce startup time and memory usage // kwrapper5 does not return useful error codes such as the exit code of ksmserver. // We only check for 255 which means that the ksmserver process could not be // started, any problems thereafter, e.g. ksmserver failing to initialize, // will remain undetected. // If the session should be locked from the start (locked autologin), // lock now and do the rest of the KDE startup underneath the locker. QStringList ksmserverOptions = { CMAKE_INSTALL_FULL_BINDIR "/ksmserver" }; if (dl) { ksmserverOptions << "--lockscreen"; } const auto exitCode = runSync("kwrapper5", ksmserverOptions); if (exitCode == 255) { // Startup error messageBox("startkde: Could not start ksmserver. Check your installation.\n"); return false; } return true; } void waitForKonqi() { - const auto cfg = KSharedConfig::openConfig("startkderc"); - KConfigGroup grp(cfg, "WaitForDrKonqi"); + const KConfig cfg("startkderc"); + const KConfigGroup grp = cfg.group("WaitForDrKonqi"); bool wait_drkonqi = grp.readEntry("Enabled", true); if (wait_drkonqi) { // wait for remaining drkonqi instances with timeout (in seconds) const int wait_drkonqi_timeout = grp.readEntry("Timeout", 900) * 1000; QElapsedTimer wait_drkonqi_counter; wait_drkonqi_counter.start(); QStringList services = allServices(QLatin1String("org.kde.drkonqi-")); while (!services.isEmpty()) { sleep(5); services = allServices(QLatin1String("org.kde.drkonqi-")); if (wait_drkonqi_counter.elapsed() >= wait_drkonqi_timeout) { // ask remaining drkonqis to die in a graceful way for (const auto &service: services) { QDBusInterface iface(service, "/MainApplication"); iface.call("quit"); } break; } } } } diff --git a/startkde/startplasma.h b/startkde/startplasma.h index 2264da27f..f7fd586ea 100644 --- a/startkde/startplasma.h +++ b/startkde/startplasma.h @@ -1,64 +1,63 @@ /* This file is part of the KDE project Copyright (C) 2019 Aleix Pol Gonzalez 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 STARTPLASMA_H #define STARTPLASMA_H #include "kcheckrunning/kcheckrunning.h" -#include "kstartupconfig/kstartupconfig.h" #include #include "config-startplasma.h" extern QTextStream out; QStringList allServices(const QLatin1String& prefix); int runSync(const QString& program, const QStringList &args, const QStringList &env = {}); void writeFile(const QString& path, const QByteArray& contents); void sourceFiles(const QStringList &files); void messageBox(const QString &text); -bool createStartupConfig(); +void createConfigDirectory(); void runStartupConfig(); void setupCursor(bool wayland); void runEnvironmentScripts(); void setupPlasmaEnvironment(); void cleanupPlasmaEnvironment(); void cleanupX11(); bool syncDBusEnvironment(); void setupFontDpi(); QProcess* setupKSplash(); void setupGSLib(); void setupX11(); bool startKDEInit(); bool startKSMServer(); void waitForKonqi(); struct KillBeforeDeleter { static inline void cleanup(QProcess *pointer) { if (pointer) pointer->kill(); delete pointer; } }; #endif