Skip to content

Commit dcffb79

Browse files
author
Camilo Higuita
committed
initial work on startup script prior to session management
1 parent 4cd6b58 commit dcffb79

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2816
-22
lines changed

CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ include(KDECMakeSettings)
2020
include(ECMInstallIcons)
2121
include(ECMAddAppIcon)
2222
include(ECMSetupVersion)
23+
include(ECMConfiguredInstall)
24+
include(ECMQtDeclareLoggingCategory)
25+
2326
include(FeatureSummary)
2427

2528
ecm_setup_version(${CASK_VERSION}
@@ -32,6 +35,7 @@ ecm_setup_version(${CASK_VERSION}
3235

3336
set(QML_IMPORT_PATH ${CMAKE_SOURCE_DIR}/plugins ${CMAKE_BINARY_DIR}/org CACHE STRING "" FORCE)
3437

38+
add_subdirectory(startcask)
3539
add_subdirectory(plugins)
3640
add_subdirectory(src)
3741

src/CMakeLists.txt

-22
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,8 @@ add_executable(${PROJECT_NAME}
2424

2525
target_link_libraries(${PROJECT_NAME} CaskLib Qt5::Qml Qt5::Quick Qt5::QuickControls2 Qt5::Svg KF5::Service Qt5::WaylandCompositor KF5::I18n KF5::ConfigCore)
2626

27-
28-
add_executable(
29-
startcask
30-
31-
startcask.cpp
32-
)
33-
34-
target_link_libraries(
35-
startcask
36-
37-
Qt5::Core
38-
)
39-
40-
install(TARGETS startcask DESTINATION ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
41-
4227
install(TARGETS ${PROJECT_NAME} ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
4328

44-
install(FILES cask.desktop DESTINATION share/wayland-sessions/)
45-
install(FILES cask-x11.desktop DESTINATION share/xsessions/)
46-
install(
47-
FILES startcask-x11
48-
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
49-
DESTINATION bin/
50-
)
5129

5230
#install(FILES org.kde.pix.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
5331

startcask/CMakeLists.txt

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
2+
DocTools Runner Notifications NotifyConfig Su Wallet IdleTime
3+
Declarative I18n Crash GlobalAccel DBusAddons Wayland
4+
CoreAddons People ActivitiesStats Activities KIO Prison Package
5+
Archive IconThemes UnitConversion ItemModels Init TextEditor)
6+
7+
find_package(KDED CONFIG REQUIRED)
8+
9+
find_package(Fontconfig)
10+
set_package_properties(Fontconfig PROPERTIES DESCRIPTION "Font access configuration library"
11+
URL "https://www.freedesktop.org/wiki/Software/fontconfig"
12+
TYPE OPTIONAL
13+
PURPOSE "Needed to build font configuration and installation tools"
14+
)
15+
if(FONTCONFIG_FOUND)
16+
# kfontinst
17+
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS PrintSupport)
18+
endif()
19+
20+
find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE)
21+
set_package_properties(Phonon4Qt5 PROPERTIES
22+
DESCRIPTION "Qt-based audio library"
23+
TYPE REQUIRED)
24+
25+
add_subdirectory(caskautostart)
26+
#add_subdirectory(kcminit)
27+
#add_subdirectory(waitforname)
28+
29+
#if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
30+
# add_subdirectory(systemd)
31+
#endif()
32+
33+
#add_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII)
34+
#add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
35+
36+
#qt_add_dbus_interface(
37+
#startplasma_SRCS
38+
#${CMAKE_SOURCE_DIR}/ksplash/ksplashqml/org.kde.KSplash.xml
39+
#ksplashinterface
40+
#)
41+
42+
set(startcask_SRCS
43+
autostartscriptdesktopfile.cpp
44+
updatelaunchenvjob.cpp
45+
)
46+
47+
ecm_qt_declare_logging_category(startcask_SRCS HEADER debug.h IDENTIFIER CASK_STARTUP CATEGORY_NAME org.cask.startup)
48+
49+
include_directories(
50+
${CMAKE_CURRENT_SOURCE_DIR}
51+
${CMAKE_CURRENT_BINARY_DIR}
52+
)
53+
54+
add_library(startcask OBJECT startcask.cpp ${startcask_SRCS})
55+
target_link_libraries(startcask PUBLIC
56+
Qt::Core
57+
Qt::DBus
58+
KF5::ConfigCore
59+
KF5::Notifications
60+
KF5::Package
61+
${PHONON_LIBRARIES}
62+
#PW::KWorkspace
63+
#lookandfeelmanager
64+
)
65+
66+
add_executable(startcask-wayland ${START_CASK_COMMON_SRCS} startcask-wayland.cpp)
67+
68+
target_link_libraries(startcask-wayland PRIVATE
69+
startcask
70+
)
71+
message( "CASKSTARTUP" ${CMAKE_CURRENT_BINARY_DIR})
72+
#add_subdirectory(cask-session)
73+
#add_subdirectory(plasma-shutdown)
74+
75+
#FIXME: reconsider, looks fishy
76+
if(NOT CMAKE_INSTALL_PREFIX STREQUAL "/usr")
77+
set_property(SOURCE startcask.cpp APPEND PROPERTY COMPILE_DEFINITIONS
78+
XCURSOR_PATH="${KDE_INSTALL_FULL_DATAROOTDIR}/icons:$XCURSOR_PATH:~/.icons:/usr/share/icons:/usr/share/pixmaps:/usr/X11R6/lib/X11/icons")
79+
endif()
80+
81+
configure_file(config-startcask.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-startcask.h)
82+
83+
install(TARGETS startcask-wayland ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
84+
install(PROGRAMS cask-sourceenv.sh DESTINATION ${KDE_INSTALL_LIBEXECDIR})
85+
install(PROGRAMS cask-dbus-run-session-if-needed DESTINATION ${KDE_INSTALL_LIBEXECDIR})
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
SPDX-FileCopyrightText: 2021 Henri Chain <[email protected]>
3+
SPDX-License-Identifier: LGPL-2.1-or-later
4+
*/
5+
6+
#include "autostartscriptdesktopfile.h"
7+
#include <KConfigGroup>
8+
#include <KDesktopFile>
9+
#include <QDir>
10+
#include <QStandardPaths>
11+
12+
static const auto autostartScriptKey = QStringLiteral("X-KDE-AutostartScript");
13+
14+
QDir AutostartScriptDesktopFile::autostartLocation()
15+
{
16+
return QDir(QDir(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation)).filePath("autostart"));
17+
}
18+
19+
AutostartScriptDesktopFile::AutostartScriptDesktopFile(const QString &name, const QString &execPath)
20+
: KDesktopFile(autostartLocation().absoluteFilePath(name + QStringLiteral(".desktop")))
21+
{
22+
KConfigGroup kcg = desktopGroup();
23+
kcg.writeEntry("Type", "Application");
24+
kcg.writeEntry("Name", name);
25+
kcg.writeEntry("Exec", execPath);
26+
kcg.writeEntry("Icon", "dialog-scripts");
27+
kcg.writeEntry(autostartScriptKey, "true");
28+
kcg.writeEntry("Path", "");
29+
}
30+
31+
bool AutostartScriptDesktopFile::isAutostartScript(const KDesktopFile &file)
32+
{
33+
return file.desktopGroup().readEntry<bool>(autostartScriptKey, false);
34+
}
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
SPDX-FileCopyrightText: 2021 Henri Chain <[email protected]>
3+
SPDX-License-Identifier: LGPL-2.1-or-later
4+
*/
5+
6+
#pragma once
7+
8+
#include <KDesktopFile>
9+
#include <QDir>
10+
#include <QString>
11+
12+
/**
13+
* Corresponds to a .desktop file in $XDG_CONFIG_HOME/autostart that points to
14+
* an autostart script and has X-KDE-AutostartScript=true
15+
*/
16+
class AutostartScriptDesktopFile : public KDesktopFile
17+
{
18+
public:
19+
explicit AutostartScriptDesktopFile(const QString &name, const QString &execPath);
20+
21+
/**
22+
* Checks whether this KDesktopFile has X-KDE-AutostartScript=true
23+
*/
24+
static bool isAutostartScript(const KDesktopFile &file);
25+
26+
/**
27+
* The location of autostart .desktop application and script files
28+
* ($XDG_CONFIG_HOME/autostart)
29+
*/
30+
static QDir autostartLocation();
31+
};
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
# Usage: plasma-dbus-run-session-if-needed PROGRAM [ARGUMENTS]
3+
# If the session bus is not available it is spawned and wrapper round our program
4+
# Otherwise we spawn our program directly
5+
drs=
6+
if [ -z "${DBUS_SESSION_BUS_ADDRESS}" ]
7+
then
8+
drs=dbus-run-session
9+
fi
10+
exec ${drs} "$@"

startcask/cask-session/CMakeLists.txt

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
add_subdirectory(plasma-autostart-list)
2+
3+
set(plasma_session_SRCS
4+
main.cpp
5+
autostart.cpp
6+
startup.cpp
7+
sessiontrack.cpp
8+
signalhandler.cpp
9+
)
10+
11+
ecm_qt_declare_logging_category(plasma_session_SRCS HEADER debug.h IDENTIFIER PLASMA_SESSION CATEGORY_NAME org.kde.plasma.session)
12+
13+
qt_add_dbus_adaptor( plasma_session_SRCS org.kde.Startup.xml startup.h Startup)
14+
15+
set(kcminit_adaptor ${plasma-workspace_SOURCE_DIR}/startkde/kcminit/main.h)
16+
set(kcminit_xml ${CMAKE_CURRENT_BINARY_DIR}/org.kde.KCMinit.xml)
17+
qt5_generate_dbus_interface( ${kcminit_adaptor} ${kcminit_xml} )
18+
qt_add_dbus_interface( plasma_session_SRCS ${kcminit_xml} kcminit_interface )
19+
qt_add_dbus_interface( plasma_session_SRCS ${KDED_DBUS_INTERFACE} kded_interface )
20+
21+
qt_add_dbus_interface( plasma_session_SRCS ../../ksmserver/org.kde.KSMServerInterface.xml ksmserver_interface )
22+
23+
add_executable(plasma_session ${plasma_session_SRCS})
24+
25+
target_include_directories(plasma_session PRIVATE ${CMAKE_SOURCE_DIR}/startkde ${CMAKE_BINARY_DIR}/startkde)
26+
target_link_libraries(plasma_session
27+
startplasma
28+
KF5::KIOCore
29+
PlasmaAutostart
30+
)
31+
32+
install(TARGETS plasma_session ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
33+

startcask/cask-session/README

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This application runs all kcminit/autostart scripts needed for a plasma session.
2+
3+
This application should only contain tasks relating to starting executables and setting environment variables so that an implementation of systemd units would not cause duplication.

startcask/cask-session/autostart.cpp

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
SPDX-FileCopyrightText: 2001 Waldo Bastian <[email protected]>
3+
4+
SPDX-License-Identifier: LGPL-2.0-only
5+
*/
6+
7+
#include "autostart.h"
8+
9+
#include "../plasmaautostart/plasmaautostart.h"
10+
11+
#include <QDir>
12+
#include <QHash>
13+
#include <QStandardPaths>
14+
15+
AutoStart::AutoStart()
16+
: m_phase(-1)
17+
, m_phasedone(false)
18+
{
19+
loadAutoStartList();
20+
}
21+
22+
AutoStart::~AutoStart()
23+
{
24+
}
25+
26+
void AutoStart::setPhase(int phase)
27+
{
28+
if (phase > m_phase) {
29+
m_phase = phase;
30+
m_phasedone = false;
31+
}
32+
}
33+
34+
void AutoStart::setPhaseDone()
35+
{
36+
m_phasedone = true;
37+
}
38+
39+
static QString extractName(QString path) // krazy:exclude=passbyvalue
40+
{
41+
int i = path.lastIndexOf(QLatin1Char('/'));
42+
if (i >= 0) {
43+
path = path.mid(i + 1);
44+
}
45+
i = path.lastIndexOf(QLatin1Char('.'));
46+
if (i >= 0) {
47+
path.truncate(i);
48+
}
49+
return path;
50+
}
51+
52+
void AutoStart::loadAutoStartList()
53+
{
54+
// XDG autostart dirs
55+
56+
// Make unique list of relative paths
57+
QHash<QString, QString> files;
58+
const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("autostart"), QStandardPaths::LocateDirectory);
59+
for (const QString &dir : dirs) {
60+
const QDir d(dir);
61+
const QStringList fileNames = d.entryList(QStringList() << QStringLiteral("*.desktop"));
62+
for (const QString &file : fileNames) {
63+
if (!files.contains(file)) {
64+
files.insert(file, d.absoluteFilePath(file));
65+
}
66+
}
67+
}
68+
69+
for (auto it = files.constBegin(); it != files.constEnd(); ++it) {
70+
PlasmaAutostart config(*it);
71+
if (!config.autostarts(QStringLiteral("KDE"), PlasmaAutostart::CheckAll)) {
72+
continue;
73+
}
74+
75+
AutoStartItem item;
76+
item.service = *it;
77+
item.name = extractName(it.key());
78+
item.startAfter = config.startAfter();
79+
item.phase = qMax(PlasmaAutostart::BaseDesktop, config.startPhase());
80+
m_startList.append(item);
81+
}
82+
}
83+
84+
QString AutoStart::startService()
85+
{
86+
if (m_startList.isEmpty()) {
87+
return QString();
88+
}
89+
90+
while (!m_started.isEmpty()) {
91+
// Check for items that depend on previously started items
92+
QString lastItem = m_started[0];
93+
QMutableVectorIterator<AutoStartItem> it(m_startList);
94+
while (it.hasNext()) {
95+
const auto &item = it.next();
96+
if (item.phase == m_phase && item.startAfter == lastItem) {
97+
m_started.prepend(item.name);
98+
QString service = item.service;
99+
it.remove();
100+
return service;
101+
}
102+
}
103+
m_started.removeFirst();
104+
}
105+
106+
// Check for items that don't depend on anything
107+
QMutableVectorIterator<AutoStartItem> it(m_startList);
108+
while (it.hasNext()) {
109+
const auto &item = it.next();
110+
if (item.phase == m_phase && item.startAfter.isEmpty()) {
111+
m_started.prepend(item.name);
112+
QString service = item.service;
113+
it.remove();
114+
return service;
115+
}
116+
}
117+
118+
// Just start something in this phase
119+
it = m_startList;
120+
while (it.hasNext()) {
121+
const auto &item = it.next();
122+
if (item.phase == m_phase) {
123+
m_started.prepend(item.name);
124+
QString service = item.service;
125+
it.remove();
126+
return service;
127+
}
128+
}
129+
130+
return QString();
131+
}
132+
133+
QVector<AutoStartItem> AutoStart::startList() const
134+
{
135+
QVector<AutoStartItem> ret;
136+
for (const auto &asi : m_startList) {
137+
if (asi.phase == m_phase)
138+
ret << asi;
139+
}
140+
return ret;
141+
}

0 commit comments

Comments
 (0)