diff --git a/plasma.desktop.cmake b/plasma.desktop.cmake --- a/plasma.desktop.cmake +++ b/plasma.desktop.cmake @@ -1,7 +1,7 @@ [Desktop Entry] Type=XSession -Exec=${CMAKE_INSTALL_FULL_BINDIR}/startkde -TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startkde +Exec=${CMAKE_INSTALL_FULL_BINDIR}/startplasma-x11 +TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startplasma-x11 DesktopNames=KDE Name=Plasma Name[ar]=بلازما diff --git a/plasmawayland.desktop.cmake b/plasmawayland.desktop.cmake --- a/plasmawayland.desktop.cmake +++ b/plasmawayland.desktop.cmake @@ -1,6 +1,6 @@ [Desktop Entry] -Exec=dbus-run-session ${CMAKE_INSTALL_FULL_BINDIR}/startplasmacompositor -TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startplasmacompositor +Exec=dbus-run-session ${CMAKE_INSTALL_FULL_BINDIR}/startplasma-wayland +TryExec=${CMAKE_INSTALL_FULL_BINDIR}/startplasma-wayland DesktopNames=KDE Name=Plasma Name[ar]=بلازما diff --git a/startkde/CMakeLists.txt b/startkde/CMakeLists.txt --- a/startkde/CMakeLists.txt +++ b/startkde/CMakeLists.txt @@ -1,20 +1,36 @@ add_subdirectory(kcminit) -add_subdirectory(kstartupconfig) add_subdirectory(ksyncdbusenv) add_subdirectory(waitforname) -add_subdirectory(kcheckrunning) + +add_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII) +add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) +add_definitions(-DQT_NO_URL_CAST_FROM_STRING) + +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 ${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(EXPORT_XCURSOR_PATH "XCURSOR_PATH=${KDE_INSTALL_FULL_DATAROOTDIR}/icons:$XCURSOR_PATH\":~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons\"; export XCURSOR_PATH") + 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(startkde.cmake ${CMAKE_CURRENT_BINARY_DIR}/startkde @ONLY) -configure_file(startplasmacompositor.cmake ${CMAKE_CURRENT_BINARY_DIR}/startplasmacompositor @ONLY) -configure_file(startplasma.cmake ${CMAKE_CURRENT_BINARY_DIR}/startplasma @ONLY) +configure_file(config-startplasma.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-startplasma.h) -if(NOT WIN32) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/startkde DESTINATION ${KDE_INSTALL_BINDIR}) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/startplasmacompositor DESTINATION ${KDE_INSTALL_BINDIR}) - install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/startplasma DESTINATION ${KDE_INSTALL_LIBEXECDIR}) -endif() +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/config-startplasma.h.cmake b/startkde/config-startplasma.h.cmake new file mode 100644 --- /dev/null +++ b/startkde/config-startplasma.h.cmake @@ -0,0 +1,10 @@ +#ifndef CONFIG_STARTPLASMA_H +#define CONFIG_STARTPLASMA_H + +#define CMAKE_INSTALL_FULL_BINDIR "@CMAKE_INSTALL_FULL_BINDIR@" +#define KDE_INSTALL_FULL_DATAROOTDIR "@KDE_INSTALL_FULL_DATAROOTDIR@" +#define CMAKE_INSTALL_FULL_LIBEXECDIR "@CMAKE_INSTALL_FULL_LIBEXECDIR@" +#define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "@CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@" +#define KWIN_WAYLAND_BIN_PATH "@KWIN_WAYLAND_BIN_PATH@" + +#endif diff --git a/startkde/kcheckrunning/CMakeLists.txt b/startkde/kcheckrunning/CMakeLists.txt deleted file mode 100644 --- a/startkde/kcheckrunning/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(kcheckrunning_SRCS - kcheckrunning.cpp) - -add_executable( kcheckrunning ${kcheckrunning_SRCS}) - -target_link_libraries(kcheckrunning ${X11_LIBRARIES}) -target_include_directories(kcheckrunning PRIVATE ${X11_X11_INCLUDE_PATH}) - -install(TARGETS kcheckrunning ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/startkde/kcheckrunning/kcheckrunning.cpp b/startkde/kcheckrunning/kcheckrunning.h copy from startkde/kcheckrunning/kcheckrunning.cpp copy to startkde/kcheckrunning/kcheckrunning.h --- a/startkde/kcheckrunning/kcheckrunning.cpp +++ b/startkde/kcheckrunning/kcheckrunning.h @@ -1,5 +1,5 @@ /* This file is part of the KDE project - Copyright (C) 2005 Lubos Lunak + 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 @@ -17,17 +17,15 @@ Boston, MA 02110-1301, USA. */ -#include +#ifndef KCHECKRUNNING_H +#define KCHECKRUNNING_H -/* - Return 0 when KDE is running, 1 when KDE is not running but it is possible - to connect to X, 2 when it's not possible to connect to X. -*/ -int main() - { - Display* dpy = XOpenDisplay( nullptr ); - if( dpy == nullptr ) - return 2; - Atom atom = XInternAtom( dpy, "_KDE_RUNNING", False ); - return XGetSelectionOwner( dpy, atom ) != None ? 0 : 1; - } +enum CheckRunningState { + PlasmaRunning, + NoPlasmaRunning, + NoX11 +}; + +CheckRunningState kCheckRunning(); + +#endif diff --git a/startkde/kcheckrunning/kcheckrunning.cpp b/startkde/kcheckrunning/kcheckrunning.cpp --- a/startkde/kcheckrunning/kcheckrunning.cpp +++ b/startkde/kcheckrunning/kcheckrunning.cpp @@ -18,16 +18,17 @@ */ #include +#include "kcheckrunning.h" /* Return 0 when KDE is running, 1 when KDE is not running but it is possible to connect to X, 2 when it's not possible to connect to X. */ -int main() - { +CheckRunningState kCheckRunning() +{ Display* dpy = XOpenDisplay( nullptr ); if( dpy == nullptr ) - return 2; + return NoX11; Atom atom = XInternAtom( dpy, "_KDE_RUNNING", False ); - return XGetSelectionOwner( dpy, atom ) != None ? 0 : 1; - } + return XGetSelectionOwner( dpy, atom ) != None ? PlasmaRunning : NoPlasmaRunning; +} diff --git a/startkde/kstartupconfig/CMakeLists.txt b/startkde/kstartupconfig/CMakeLists.txt deleted file mode 100644 --- a/startkde/kstartupconfig/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -########### kstartupconfig ############### - -set(kstartupconfig_SRCS kstartupconfig.cpp ) - -add_executable(kstartupconfig5 ${kstartupconfig_SRCS}) - -install(TARGETS kstartupconfig5 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) - -########### kdostartupconfig ############### - -set(kdostartupconfig_SRCS kdostartupconfig.cpp ) - -add_executable(kdostartupconfig5 ${kdostartupconfig_SRCS}) - -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 --- 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 << 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 << 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 --- 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 main() -{ - 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/plasma-sourceenv.sh b/startkde/plasma-sourceenv.sh new file mode 100644 --- /dev/null +++ b/startkde/plasma-sourceenv.sh @@ -0,0 +1,6 @@ +for i in $@ +do + . $i >/dev/null +done + +env diff --git a/startkde/startkde.cmake b/startkde/startkde.cmake deleted file mode 100644 --- a/startkde/startkde.cmake +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/sh -# -# DEFAULT Plasma STARTUP SCRIPT ( @PROJECT_VERSION@ ) -# - -# When the X server dies we get a HUP signal from xinit. We must ignore it -# because we still need to do some cleanup. -trap 'echo GOT SIGHUP' HUP - -# Check if a Plasma session already is running and whether it's possible to connect to X -kcheckrunning -kcheckrunning_result=$? -if test $kcheckrunning_result -eq 0 ; then - echo "Plasma seems to be already running on this display." - xmessage -geometry 500x100 "Plasma seems to be already running on this display." > /dev/null 2>/dev/null - exit 1 -elif test $kcheckrunning_result -eq 2 ; then - echo "\$DISPLAY is not set or cannot connect to the X server." - exit 1 -fi - -# 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 - -if [ ${XDG_CONFIG_HOME} ]; then - configDir=$XDG_CONFIG_HOME; -else - configDir=${HOME}/.config; #this is the default, http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -fi -sysConfigDirs=${XDG_CONFIG_DIRS:-/etc/xdg} - -# We need to create config folder so we can write startupconfigkeys -mkdir -p $configDir - -#This is basically setting defaults so we can use them with kstartupconfig5 -cat >$configDir/startupconfigkeys <$plasmalocalerc </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. - -scriptpath=`echo "$configDir:$sysConfigDirs" | tr ':' '\n'` - -for prefix in `echo $scriptpath`; do - for file in "$prefix"/plasma-workspace/env/*.sh; do - test -r "$file" && . "$file" || true - done -done - -# 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. -# -xsetroot -cursor_name left_ptr - -# Get Ghostscript to look into user's KDE fonts dir for additional Fontmap -usr_fdir=$HOME/.fonts -if test -n "$GS_LIB" ; then - GS_LIB=$usr_fdir:$GS_LIB - export GS_LIB -else - GS_LIB=$usr_fdir - export GS_LIB -fi - -echo 'startkde: Starting up...' 1>&2 - -# 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 test -z "$XDG_DATA_DIRS"; then - XDG_DATA_DIRS="@KDE_INSTALL_FULL_DATAROOTDIR@:/usr/share:/usr/local/share" -fi -export XDG_DATA_DIRS - -# 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: -# xprop -root | grep "^KDE_FULL_SESSION" >/dev/null 2>/dev/null -# if test $? -eq 0; then ... whatever -# -# Additionally there is (since KDE 3.5.7) $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. -# Note that this didn't exist in KDE3, which can be detected by its absense and -# the presence of KDE_FULL_SESSION. -# -KDE_FULL_SESSION=true -export KDE_FULL_SESSION -xprop -root -f KDE_FULL_SESSION 8t -set KDE_FULL_SESSION true - -KDE_SESSION_VERSION=5 -export KDE_SESSION_VERSION -xprop -root -f KDE_SESSION_VERSION 32c -set KDE_SESSION_VERSION 5 - -KDE_SESSION_UID=`id -ru` -export KDE_SESSION_UID - -XDG_CURRENT_DESKTOP=KDE -export XDG_CURRENT_DESKTOP - -# At this point all environment variables are set, let's send it to the DBus session server to update the activation environment -if which dbus-update-activation-environment >/dev/null 2>/dev/null ; then - dbus-update-activation-environment --systemd --all -else - @CMAKE_INSTALL_FULL_LIBEXECDIR@/ksyncdbusenv -fi -if test $? -ne 0; then - # Startup error - echo 'startkde: Could not sync environment to dbus.' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - xmessage -geometry 500x100 "Could not sync environment to dbus." - exit 1 -fi - -# We set LD_BIND_NOW to increase the efficiency of kdeinit. -# kdeinit unsets this variable before loading applications. -LD_BIND_NOW=true @CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@/start_kdeinit_wrapper --kded +kcminit_startup -if test $? -ne 0; then - # Startup error - echo 'startkde: Could not start kdeinit5. Check your installation.' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - xmessage -geometry 500x100 "Could not start kdeinit5. Check your installation." - exit 1 -fi - -qdbus org.kde.KSplash /KSplash org.kde.KSplash.setStage kinit & - -# 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. -test -n "$KDEWM" && KDEWM="--windowmanager $KDEWM" -# If the session should be locked from the start (locked autologin), -# lock now and do the rest of the KDE startup underneath the locker. -KSMSERVEROPTIONS="" -test -n "$dl" && KSMSERVEROPTIONS=" --lockscreen" -kwrapper5 @CMAKE_INSTALL_FULL_BINDIR@/ksmserver $KDEWM $KSMSERVEROPTIONS -if test $? -eq 255; then - # Startup error - echo 'startkde: Could not start ksmserver. Check your installation.' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - xmessage -geometry 500x100 "Could not start ksmserver. Check your installation." -fi - -#Anything after here is logout -#It is not called after shutdown/restart - -wait_drkonqi=`kreadconfig5 --file startkderc --group WaitForDrKonqi --key Enabled --default true` - -if test x"$wait_drkonqi"x = x"true"x ; then - # wait for remaining drkonqi instances with timeout (in seconds) - wait_drkonqi_timeout=`kreadconfig5 --file startkderc --group WaitForDrKonqi --key Timeout --default 900` - wait_drkonqi_counter=0 - while qdbus | grep "^[^w]*org.kde.drkonqi" > /dev/null ; do - sleep 5 - wait_drkonqi_counter=$((wait_drkonqi_counter+5)) - if test "$wait_drkonqi_counter" -ge "$wait_drkonqi_timeout" ; then - # ask remaining drkonqis to die in a graceful way - qdbus | grep 'org.kde.drkonqi-' | while read address ; do - qdbus "$address" "/MainApplication" "quit" - done - break - fi - done -fi - -echo 'startkde: Shutting down...' 1>&2 -# just in case -test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - -# Clean up -kdeinit5_shutdown - -unset KDE_FULL_SESSION -xprop -root -remove KDE_FULL_SESSION -unset KDE_SESSION_VERSION -xprop -root -remove KDE_SESSION_VERSION -unset KDE_SESSION_UID - -echo 'startkde: Done.' 1>&2 diff --git a/startkde/startplasma-wayland.cpp b/startkde/startplasma-wayland.cpp new file mode 100644 --- /dev/null +++ b/startkde/startplasma-wayland.cpp @@ -0,0 +1,92 @@ +/* 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 + +int main(int /*argc*/, char** /*argv*/) +{ + createConfigDirectory(); + setupCursor(true); + + { + KConfig fonts(QStringLiteral("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. + { + const QString locale1Service = QStringLiteral("org.freedesktop.locale1"); + const QString locale1Path = QStringLiteral("/org/freedesktop/locale1"); + QDBusMessage message = QDBusMessage::createMethodCall(locale1Service, + locale1Path, + QStringLiteral("org.freedesktop.DBus.Properties"), + QLatin1String("GetAll")); + message << locale1Service; + QDBusMessage resultMessage = QDBusConnection::systemBus().call(message); + if (resultMessage.type() == QDBusMessage::ReplyMessage) { + QVariantMap result; + QDBusArgument dbusArgument = resultMessage.arguments().at(0).value(); + while (!dbusArgument.atEnd()) { + dbusArgument >> result; + } + + auto queryAndSet = [&](const QByteArray &var, const QString & value) { + const auto r = result.value(value).toString(); + if (!r.isEmpty()) + qputenv(var, r.toUtf8()); + }; + + queryAndSet("X11MODEL", QStringLiteral("X11Model")); + queryAndSet("X11LAYOUT", QStringLiteral("X11Layout")); + queryAndSet("X11VARIANT", QStringLiteral("X11Variant")); + queryAndSet("X11OPTIONS", QStringLiteral("X11Options")); + } else { + qWarning() << "not a reply org.freedesktop.locale1" << resultMessage; + } + } + 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(QStringLiteral(KWIN_WAYLAND_BIN_PATH), { QStringLiteral("--xwayland"), QStringLiteral("--libinput"), QStringLiteral("--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-waylandsession.cpp b/startkde/startplasma-waylandsession.cpp new file mode 100644 --- /dev/null +++ b/startkde/startplasma-waylandsession.cpp @@ -0,0 +1,76 @@ +/* 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" + +int main(int /*argc*/, char** /*argv*/) +{ + // 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 + + runStartupConfig(); + + setupFontDpi(); + + QScopedPointer ksplash(setupKSplash()); + qputenv("PLASMA_USE_QT_SCALING", "1"); + + out << "startplasma-waylandsession: Starting up..."; + + if (qEnvironmentVariableIsSet("DISPLAY")) { + setupX11(); + } else { + qWarning() << "running kwin without Xwayland support"; + } + setupGSLib(); + + if (!syncDBusEnvironment()) { + out << "Could not sync environment to dbus.\n"; + return 2; + } + + if (!startKDEInit()) + return 3; + + if (!startKSMServer()) + return 4; + + // Anything after here is logout + // It is not called after shutdown/restart + waitForKonqi(); + out << "startplasma-waylandsession: Shutting down...\n"; + + runSync(QStringLiteral("kdeinit5_shutdown"), {}); + + cleanupX11(); + out << "startplasma-waylandsession: Done.\n"; + + return 0; +} diff --git a/startkde/startplasma-x11.cpp b/startkde/startplasma-x11.cpp new file mode 100644 --- /dev/null +++ b/startkde/startplasma-x11.cpp @@ -0,0 +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 + +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(QStringLiteral("Plasma seems to be already running on this display.\n")); + return 1; + case NoPlasmaRunning: + break; + } + + createConfigDirectory(); + runStartupConfig(); + + //Do not sync any of this section with the wayland versions as there scale factors are + //sent properly over wl_output + + { + KConfig cfg(QStringLiteral("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.toDouble(), 'g', 3)); + } + } + } + + setupCursor(false); + setupFontDpi(); + QScopedPointer ksplash(setupKSplash()); + + runEnvironmentScripts(); + + out << "startkde: Starting up...\n"; + + setupPlasmaEnvironment(); + setupX11(); + + if (!syncDBusEnvironment()) { + // Startup error + messageBox(QStringLiteral("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(QStringLiteral("kdeinit5_shutdown"), {}); + + cleanupPlasmaEnvironment(); + cleanupX11(); + + out << "startkde: Done.\n"; + + return 0; +} diff --git a/startkde/startplasma.h b/startkde/startplasma.h new file mode 100644 --- /dev/null +++ b/startkde/startplasma.h @@ -0,0 +1,62 @@ +/* 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 +#include "config-startplasma.h" + +extern QTextStream out; + +QStringList allServices(const QLatin1String& prefix); +int runSync(const QString& program, const QStringList &args, const QStringList &env = {}); +void sourceFiles(const QStringList &files); +void messageBox(const QString &text); + +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 diff --git a/startkde/startplasma.cmake b/startkde/startplasma.cmake deleted file mode 100644 --- a/startkde/startplasma.cmake +++ /dev/null @@ -1,160 +0,0 @@ -#!/bin/sh -# -# DEFAULT Plasma STARTUP SCRIPT ( @PROJECT_VERSION@ ) -# - -# 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 - -# We need to create config folder so we can write startupconfigkeys -if [ ${XDG_CONFIG_HOME} ]; then - configDir=$XDG_CONFIG_HOME; -else - configDir=${HOME}/.config; #this is the default, http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -fi - -[ -r $configDir/startupconfig ] && . $configDir/startupconfig - -xrdb -quiet -merge -nocpp <&2 - -# export our session variables to the Xwayland server -xprop -root -f KDE_FULL_SESSION 8t -set KDE_FULL_SESSION true -xprop -root -f KDE_SESSION_VERSION 32c -set KDE_SESSION_VERSION 5 - -# At this point all environment variables are set, let's send it to the DBus session server to update the activation environment -if which dbus-update-activation-environment >/dev/null 2>/dev/null ; then - dbus-update-activation-environment --systemd --all -else - @CMAKE_INSTALL_FULL_LIBEXECDIR@/ksyncdbusenv -fi -if test $? -ne 0; then - # Startup error - echo 'startplasma: Could not sync environment to dbus.' 1>&2 - exit 1 -fi - -# We set LD_BIND_NOW to increase the efficiency of kdeinit. -# kdeinit unsets this variable before loading applications. -LD_BIND_NOW=true @CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@/start_kdeinit_wrapper --kded +kcminit_startup -if test $? -ne 0; then - # Startup error - echo 'startplasma: Could not start kdeinit5. Check your installation.' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - xmessage -geometry 500x100 "Could not start kdeinit5. Check your installation." - exit 1 -fi - -qdbus org.kde.KSplash /KSplash org.kde.KSplash.setStage kinit & - -# 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. -KSMSERVEROPTIONS=" --no-lockscreen" -kwrapper5 @CMAKE_INSTALL_FULL_BINDIR@/ksmserver $KDEWM $KSMSERVEROPTIONS -if test $? -eq 255; then - # Startup error - echo 'startplasma: Could not start ksmserver. Check your installation.' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - xmessage -geometry 500x100 "Could not start ksmserver. Check your installation." -fi - -#Anything after here is logout -#It is not called after shutdown/restart - -wait_drkonqi=`kreadconfig5 --file startkderc --group WaitForDrKonqi --key Enabled --default true` - -if test x"$wait_drkonqi"x = x"true"x ; then - # wait for remaining drkonqi instances with timeout (in seconds) - wait_drkonqi_timeout=`kreadconfig5 --file startkderc --group WaitForDrKonqi --key Timeout --default 900` - wait_drkonqi_counter=0 - while qdbus | grep "^[^w]*org.kde.drkonqi" > /dev/null ; do - sleep 5 - wait_drkonqi_counter=$((wait_drkonqi_counter+5)) - if test "$wait_drkonqi_counter" -ge "$wait_drkonqi_timeout" ; then - # ask remaining drkonqis to die in a graceful way - qdbus | grep 'org.kde.drkonqi-' | while read address ; do - qdbus "$address" "/MainApplication" "quit" - done - break - fi - done -fi - -echo 'startplasma: Shutting down...' 1>&2 -# just in case -test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - -# Clean up -kdeinit5_shutdown - -unset KDE_FULL_SESSION -xprop -root -remove KDE_FULL_SESSION -unset KDE_SESSION_VERSION -xprop -root -remove KDE_SESSION_VERSION -unset KDE_SESSION_UID - -echo 'startplasma: Done.' 1>&2 diff --git a/startkde/startplasma.cpp b/startkde/startplasma.cpp new file mode 100644 --- /dev/null +++ b/startkde/startplasma.cpp @@ -0,0 +1,395 @@ +/* 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 "startplasma.h" + +QTextStream out(stderr); + +void messageBox(const QString &text) +{ + out << text; + runSync(QStringLiteral("xmessage"), {QStringLiteral("-geometry"), QStringLiteral("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); + if (p.exitCode()) { + qWarning() << program << args << "exited with code" << p.exitCode(); + } + return p.exitCode(); +} + +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(QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR "/plasma-sourceenv.sh")); + + QProcess p; + p.start(QStringLiteral("/bin/sh"), filteredFiles); + p.waitForFinished(-1); + + const auto fullEnv = p.readAllStandardOutput(); + auto envs = fullEnv.split('\n'); + + for (auto &env: envs) { + if (env.startsWith("_=") || env.startsWith("SHLVL")) + 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)); + } + } +} + +void createConfigDirectory() +{ + const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); + if (!QDir().mkpath(configDir)) + out << "Could not create config directory XDG_CONFIG_HOME: " << configDir << '\n'; +} + +void runStartupConfig() +{ + const QString configDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); + + const QString localerc(configDir + QLatin1String("/plasma-localerc")); + if (!QFile::exists(localerc)) { + QFile f(localerc); + f.open(QFile::WriteOnly); + f.write("[Formats]\n" + "LANG=" + qgetenv("LANG") + '\n'); + } + + //export LC_* variables set by kcmshell5 formats into environment + //so it can be picked up by QLocale and friends. + sourceFiles({configDir + QStringLiteral("/plasma-locale-settings.sh")}); +} + +void setupCursor(bool wayland) +{ + const KConfig cfg(QStringLiteral("kcminputrc")); + const KConfigGroup inputCfg = cfg.group("Mouse"); + + const auto kcminputrc_mouse_cursorsize = inputCfg.readEntry("cursorSize", QString()); + const auto kcminputrc_mouse_cursortheme = inputCfg.readEntry("cursorTheme", QStringLiteral("breeze_cursors")); + 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(QStringLiteral("kapplymousetheme"), { QStringLiteral("kcminputrc_mouse_cursortheme"), QStringLiteral("kcminputrc_mouse_cursorsize") }); + if (applyMouseStatus == 10) { + qputenv("XCURSOR_THEME", "breeze_cursors"); + } else if (!kcminputrc_mouse_cursortheme.isEmpty()) { + qputenv("XCURSOR_THEME", kcminputrc_mouse_cursortheme.toUtf8()); + } + if (!kcminputrc_mouse_cursorsize.isEmpty()) { + 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(QStringLiteral("xsetroot"), {QStringLiteral("-cursor_name"), QStringLiteral("left_ptr")}); + runSync(QStringLiteral("xprop"), {QStringLiteral("-root"), QStringLiteral("-f"), QStringLiteral("KDE_FULL_SESSION"), QStringLiteral("8t"), QStringLiteral("-set"), QStringLiteral("KDE_FULL_SESSION"), QStringLiteral("true")}); + runSync(QStringLiteral("xprop"), {QStringLiteral("-root"), QStringLiteral("-f"), QStringLiteral("KDE_SESSION_VERSION"), QStringLiteral("32c"), QStringLiteral("-set"), QStringLiteral("KDE_SESSION_VERSION"), QStringLiteral("5")}); +} + +void cleanupX11() +{ + runSync(QStringLiteral("xprop"), { QStringLiteral("-root"), QStringLiteral("-remove"), QStringLiteral("KDE_FULL_SESSION") }); + runSync(QStringLiteral("xprop"), { QStringLiteral("-root"), QStringLiteral("-remove"), QStringLiteral("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(QStringLiteral("dbus-update-activation-environment")).isEmpty()) { + exitCode = runSync(QStringLiteral("dbus-update-activation-environment"), { QStringLiteral("--systemd"), QStringLiteral("--all") }); + } else { + exitCode = runSync(QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR "/ksyncdbusenv"), {}); + } + return exitCode == 0; +} + +void setupFontDpi() +{ + KConfig cfg(QStringLiteral("kcmfonts")); + KConfigGroup fontsCfg(&cfg, "General"); + + if (!fontsCfg.hasKey("forceFontDPI")) { + return; + } + + //TODO port to c++? + const QByteArray input = "Xft.dpi: " + QByteArray::number(fontsCfg.readEntry("forceFontDPI", 0)); + QProcess p; + p.start(QStringLiteral("xrdb"), { QStringLiteral("-quiet"), QStringLiteral("-merge"), QStringLiteral("-nocpp") }); + p.setProcessChannelMode(QProcess::ForwardedChannels); + p.write(input); + p.closeWriteChannel(); + p.waitForFinished(-1); +} + +static bool desktopLockedAtStart = false; + +QProcess* setupKSplash() +{ + const auto dlstr = qgetenv("DESKTOP_LOCKED"); + desktopLockedAtStart = dlstr == "true" || dlstr == "1"; + qunsetenv("DESKTOP_LOCKED"); // Don't want it in the environment + + QProcess* p = nullptr; + if (!desktopLockedAtStart) { + const KConfig cfg(QStringLiteral("ksplashrc")); + // the splashscreen and progress indicator + KConfigGroup ksplashCfg = cfg.group("KSplash"); + if (ksplashCfg.readEntry("Engine", QStringLiteral("KSplashQML")) == QLatin1String("KSplashQML")) { + p = new QProcess; + p->start(QStringLiteral("ksplashqml"), { ksplashCfg.readEntry("Theme", QStringLiteral("Breeze")) }); + } + } + 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(QStringLiteral(".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(QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/start_kdeinit_wrapper"), { QStringLiteral("--kded"), QStringLiteral("+kcminit_startup") }, { QStringLiteral("LD_BIND_NOW=true") }); + if (exitCode != 0) { + messageBox(QStringLiteral("startkde: Could not start kdeinit5. Check your installation.")); + return false; + } + + OrgKdeKSplashInterface iface(QStringLiteral("org.kde.KSplash"), QStringLiteral("/KSplash"), QDBusConnection::sessionBus()); + iface.setStage(QStringLiteral("kinit")); + 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 = { QStringLiteral(CMAKE_INSTALL_FULL_BINDIR "/ksmserver") }; + if (desktopLockedAtStart) { + ksmserverOptions << QStringLiteral("--lockscreen"); + } + const auto exitCode = runSync(QStringLiteral("kwrapper5"), ksmserverOptions); + + if (exitCode == 255) { + // Startup error + messageBox(QStringLiteral("startkde: Could not start ksmserver. Check your installation.\n")); + return false; + } + return true; +} + +void waitForKonqi() +{ + const KConfig cfg(QStringLiteral("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, QStringLiteral("/MainApplication")); + iface.call(QStringLiteral("quit")); + } + break; + } + } + } +} diff --git a/startkde/startplasmacompositor.cmake b/startkde/startplasmacompositor.cmake deleted file mode 100644 --- a/startkde/startplasmacompositor.cmake +++ /dev/null @@ -1,202 +0,0 @@ -#!/bin/sh -# -# DEFAULT Plasma STARTUP SCRIPT ( @PROJECT_VERSION@ ) -# - -# We need to create config folder so we can write startupconfigkeys -if [ ${XDG_CONFIG_HOME} ]; then - configDir=$XDG_CONFIG_HOME; -else - configDir=${HOME}/.config; #this is the default, http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html -fi -sysConfigDirs=${XDG_CONFIG_DIRS:-/etc/xdg} - -# We need to create config folder so we can write startupconfigkeys -mkdir -p $configDir - -#This is basically setting defaults so we can use them with kstartupconfig5 -cat >$configDir/startupconfigkeys <$plasmalocalerc </dev/null 2>/dev/null; then - # Do not overwrite existing values. There is no point in setting only some - # of them as then they would not match anymore. - if [ -z "${XKB_DEFAULT_MODEL}" -a -z "${XKB_DEFAULT_LAYOUT}" -a \ - -z "${XKB_DEFAULT_VARIANT}" -a -z "${XKB_DEFAULT_OPTIONS}" ]; then - X11MODEL="$(queryLocale1 org.freedesktop.locale1.X11Model)" - X11LAYOUT="$(queryLocale1 org.freedesktop.locale1.X11Layout)" - X11VARIANT="$(queryLocale1 org.freedesktop.locale1.X11Variant)" - X11OPTIONS="$(queryLocale1 org.freedesktop.locale1.X11Options)" - [ -n "${X11MODEL}" ] && export XKB_DEFAULT_MODEL="${X11MODEL}" - [ -n "${X11LAYOUT}" ] && export XKB_DEFAULT_LAYOUT="${X11LAYOUT}" - [ -n "${X11VARIANT}" ] && export XKB_DEFAULT_VARIANT="${X11VARIANT}" - [ -n "${X11OPTIONS}" ] && export XKB_DEFAULT_OPTIONS="${X11OPTIONS}" - fi -fi - -# Source scripts found in /plasma-workspace/env/*.sh -# (where correspond to the system and user's configuration -# directories, as identified by Qt's qtpaths, e.g. $HOME/.config -# and /etc/xdg/ on Linux) -# -# 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. - -scriptpath=`echo "$configDir:$sysConfigDirs" | tr ':' '\n'` - -for prefix in `echo $scriptpath`; do - for file in "$prefix"/plasma-workspace/env/*.sh; do - test -r "$file" && . "$file" || true - done -done - -echo 'startplasmacompositor: Starting up...' 1>&2 - -# 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 test -z "$XDG_DATA_DIRS"; then -XDG_DATA_DIRS="@KDE_INSTALL_FULL_DATADIR@:/usr/share:/usr/local/share" -fi -export XDG_DATA_DIRS - -# Make sure that D-Bus is running -if qdbus >/dev/null 2>/dev/null; then - : # ok -else - echo 'startplasmacompositor: Could not start D-Bus. Can you call qdbus?' 1>&2 - test -n "$ksplash_pid" && kill "$ksplash_pid" 2>/dev/null - exit 1 -fi - - -# 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: -# xprop -root | grep "^KDE_FULL_SESSION" >/dev/null 2>/dev/null -# if test $? -eq 0; then ... whatever -# -# Additionally there is (since KDE 3.5.7) $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. -# Note that this didn't exist in KDE3, which can be detected by its absense and -# the presence of KDE_FULL_SESSION. -# -KDE_FULL_SESSION=true -export KDE_FULL_SESSION - -KDE_SESSION_VERSION=5 -export KDE_SESSION_VERSION - -KDE_SESSION_UID=`id -ru` -export KDE_SESSION_UID - -XDG_CURRENT_DESKTOP=KDE -export XDG_CURRENT_DESKTOP - -XDG_SESSION_TYPE=wayland -export XDG_SESSION_TYPE - -# kwin_wayland can possibly also start dbus-activated services which need env variables. -# In that case, the update in startplasma might be too late. -if which dbus-update-activation-environment >/dev/null 2>/dev/null ; then - dbus-update-activation-environment --systemd --all -else - @CMAKE_INSTALL_FULL_LIBEXECDIR@/ksyncdbusenv -fi -if test $? -ne 0; then - # Startup error - echo 'startplasmacompositor: Could not sync environment to dbus.' 1>&2 - exit 1 -fi - -@KWIN_WAYLAND_BIN_PATH@ --xwayland --libinput --exit-with-session=@CMAKE_INSTALL_FULL_LIBEXECDIR@/startplasma - -echo 'startplasmacompositor: Shutting down...' 1>&2 - -unset KDE_FULL_SESSION -unset KDE_SESSION_VERSION -unset KDE_SESSION_UID - -echo 'startplasmacompositor: Done.' 1>&2