theshell/main.cpp

416 lines
14 KiB
C++
Raw Normal View History

2017-08-05 15:20:02 +10:00
/****************************************
2017-08-07 18:08:56 +10:00
*
2017-08-05 15:20:02 +10:00
* theShell - Desktop Environment
* Copyright (C) 2017 Victor Tran
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2017-08-07 18:08:56 +10:00
*
2017-08-05 15:20:02 +10:00
* *************************************/
2016-02-17 17:24:00 +11:00
#include "mainwindow.h"
2016-03-17 19:46:40 +11:00
#include "background.h"
2016-03-29 17:42:24 +11:00
#include "loginsplash.h"
2016-05-29 17:03:52 +10:00
#include "segfaultdialog.h"
#include "globalfilter.h"
2016-06-16 20:53:49 +10:00
#include "dbusevents.h"
2016-11-25 15:24:09 +11:00
#include "onboarding.h"
2016-12-17 23:58:08 +11:00
#include "tutorialwindow.h"
2017-01-12 01:00:27 +11:00
#include "audiomanager.h"
#include "dbussignals.h"
2016-09-13 14:07:51 +10:00
#include <iostream>
2016-08-20 16:26:35 +10:00
//#include "dbusmenuregistrar.h"
2016-06-11 17:07:36 +10:00
#include <nativeeventfilter.h>
2016-02-17 17:24:00 +11:00
#include <QApplication>
2017-06-05 17:08:54 +10:00
#include <QDBusServiceWatcher>
2016-03-17 19:46:40 +11:00
#include <QDesktopWidget>
#include <QProcess>
#include <QThread>
2016-03-29 17:42:24 +11:00
#include <QUrl>
#include <QMediaPlayer>
#include <QDebug>
#include <QSettings>
#include <QInputDialog>
2016-05-29 17:03:52 +10:00
#include <signal.h>
#include <unistd.h>
#include <X11/Xlib.h>
2017-05-02 17:12:21 +10:00
#include "locationservices.h"
2016-05-29 17:03:52 +10:00
MainWindow* MainWin = NULL;
2016-06-11 17:07:36 +10:00
NativeEventFilter* NativeFilter = NULL;
2016-06-16 20:53:49 +10:00
DbusEvents* DBusEvents = NULL;
2016-12-17 23:58:08 +11:00
TutorialWindow* TutorialWin = NULL;
2017-01-12 01:00:27 +11:00
AudioManager* AudioMan = NULL;
QTranslator *qtTranslator, *tsTranslator;
2017-05-02 17:12:21 +10:00
LocationServices* locationServices = NULL;
2017-06-05 17:08:54 +10:00
QDBusServiceWatcher* dbusServiceWatcher = NULL;
QDBusServiceWatcher* dbusServiceWatcherSystem = NULL;
UPowerDBus* updbus = NULL;
NotificationDBus* ndbus = NULL;
DBusSignals* dbusSignals = NULL;
2016-05-29 17:03:52 +10:00
2017-04-24 15:49:10 +10:00
#define ONBOARDING_VERSION 4
2016-09-13 14:07:51 +10:00
void raise_signal(QString message) {
//Clean up required stuff
//Delete the Native Event Filter so that keyboard bindings are cleared
if (NativeFilter != NULL) {
2016-10-18 08:22:46 +11:00
NativeFilter->deleteLater();
2016-09-13 14:07:51 +10:00
NativeFilter = NULL;
}
SegfaultDialog* dialog;
2016-09-13 14:07:51 +10:00
dialog = new SegfaultDialog(message);
if (MainWin != NULL) {
MainWin->close();
2016-10-18 08:22:46 +11:00
MainWin->deleteLater();
2016-09-13 14:07:51 +10:00
}
dialog->exec();
raise(SIGKILL);
}
void catch_signal(int signal) {
if (signal == SIGSEGV) {
qDebug() << "SEGFAULT! Quitting now!";
2016-09-13 14:07:51 +10:00
raise_signal("Signal: SIGSEGV (Segmentation Fault)");
2016-07-01 14:01:19 +10:00
} else if (signal == SIGBUS) {
qDebug() << "SIGBUS! Quitting now!";
2016-09-13 14:07:51 +10:00
raise_signal("Signal: SIGBUS (Bus Error)");
2016-07-01 14:01:19 +10:00
} else if (signal == SIGABRT) {
qDebug() << "SIGABRT! Quitting now!";
2016-09-13 14:07:51 +10:00
raise_signal("Signal: SIGABRT (Abort)");
} else if (signal == SIGILL) {
qDebug() << "SIGILL! Quitting now!";
2016-09-13 14:07:51 +10:00
raise_signal("Signal: SIGILL (Illegal Operation)");
}
2016-09-13 14:07:51 +10:00
}
void QtHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
switch (type) {
case QtDebugMsg:
case QtInfoMsg:
case QtWarningMsg:
case QtCriticalMsg:
2017-01-15 00:38:39 +11:00
std::cerr << msg.toStdString() + "\n";
2016-09-13 14:07:51 +10:00
break;
case QtFatalMsg:
2017-01-15 00:38:39 +11:00
std::cerr << msg.toStdString() + "\n";
2016-09-13 14:07:51 +10:00
raise_signal(msg);
2016-05-29 17:03:52 +10:00
}
}
2016-02-17 17:24:00 +11:00
int main(int argc, char *argv[])
{
2016-07-22 22:47:38 +10:00
signal(SIGSEGV, *catch_signal); //Catch SIGSEGV
signal(SIGBUS, *catch_signal); //Catch SIGBUS
signal(SIGABRT, *catch_signal); //Catch SIGABRT
signal(SIGILL, *catch_signal); //Catch SIGILL
2016-05-29 17:03:52 +10:00
2017-01-22 00:08:04 +11:00
QSettings settings("theSuite", "theShell");
2017-08-04 21:18:42 +10:00
qputenv("GTK_THEME", settings.value("theme/gtktheme", "Contemporary").toByteArray());
2017-01-22 00:08:04 +11:00
QString localeName = settings.value("locale/language", "en_US").toString();
qputenv("LANG", localeName.toUtf8());
2017-01-15 00:38:39 +11:00
qInstallMessageHandler(QtHandler);
2016-09-13 14:07:51 +10:00
2016-02-17 17:24:00 +11:00
QApplication a(argc, argv);
2016-03-17 19:46:40 +11:00
2017-01-22 00:08:04 +11:00
a.setOrganizationName("theSuite");
a.setOrganizationDomain("");
a.setApplicationName("theShell");
QLocale defaultLocale(localeName);
QLocale::setDefault(defaultLocale);
if (defaultLocale.language() == QLocale::Arabic || defaultLocale.language() == QLocale::Hebrew) {
//Reverse the layout direction
a.setLayoutDirection(Qt::RightToLeft);
} else {
//Set normal layout direction
a.setLayoutDirection(Qt::LeftToRight);
2017-01-22 00:08:04 +11:00
}
qtTranslator = new QTranslator;
qtTranslator->load("qt_" + defaultLocale.name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
a.installTranslator(qtTranslator);
2017-01-22 00:08:04 +11:00
2017-02-15 22:19:30 +11:00
qDebug() << QLocale().name();
tsTranslator = new QTranslator;
tsTranslator->load(QLocale().name(), "/usr/share/theshell/translations");
a.installTranslator(tsTranslator);
2017-01-22 00:08:04 +11:00
2017-06-05 17:08:54 +10:00
dbusServiceWatcher = new QDBusServiceWatcher();
dbusServiceWatcher->setConnection(QDBusConnection::sessionBus());
dbusServiceWatcherSystem = new QDBusServiceWatcher();
dbusServiceWatcherSystem->setConnection(QDBusConnection::systemBus());
2017-01-22 00:08:04 +11:00
/*QTranslator tsVnTranslator;
tsTranslator.load(QLocale("vi_VN").name(), "/home/victor/Documents/theOSPack/theShell/translations/");
a.installTranslator(&tsVnTranslator);*/
2016-03-29 17:42:24 +11:00
bool showSplash = true;
bool autoStart = true;
2016-07-22 22:47:38 +10:00
bool startKscreen = true;
2016-11-25 15:24:09 +11:00
bool startOnboarding = false;
2016-11-29 22:05:11 +11:00
bool startWm = true;
2016-12-17 23:58:08 +11:00
bool tutorialDoSettings = false;
2016-03-29 17:42:24 +11:00
QStringList args = a.arguments();
args.removeFirst();
for (QString arg : a.arguments()) {
if (arg == "--help" || arg == "-h") {
qDebug() << "theShell";
qDebug() << "Usage: theshell [OPTIONS]";
qDebug() << " -s, --no-splash-screen Don't show the splash screen";
qDebug() << " -a, --no-autostart Don't autostart executables";
2016-07-22 22:47:38 +10:00
qDebug() << " -k, --no-kscreen Don't autostart KScreen";
2016-11-29 22:05:11 +11:00
qDebug() << " --no-wm Don't autostart the window manager";
2016-11-25 15:24:09 +11:00
qDebug() << " --onboard Start with onboarding screen";
2016-12-17 23:58:08 +11:00
qDebug() << " --tutorial Show all tutorials";
qDebug() << " --debug Allows you to quit theShell instead of powering off";
2016-03-29 17:42:24 +11:00
qDebug() << " -h, --help Show this help output";
return 0;
} else if (arg == "-s" || arg == "--no-splash-screen") {
showSplash = false;
} else if (arg == "-a" || arg == "--no-autostart") {
autoStart = false;
2016-07-22 22:47:38 +10:00
} else if (arg == "-k" || arg == "--no-kscreen") {
startKscreen = false;
2016-11-29 22:05:11 +11:00
} else if (arg == "--no-wm") {
startWm = false;
2016-11-25 15:24:09 +11:00
} else if (arg == "--onboard") {
startOnboarding = true;
2016-12-17 23:58:08 +11:00
} else if (arg == "--tutorial") {
tutorialDoSettings = true;
2016-03-29 17:42:24 +11:00
}
}
if (showSplash) {
LoginSplash* splash = new LoginSplash();
splash->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
splash->showFullScreen();
}
2016-08-29 18:51:46 +10:00
if (QDBusConnection::sessionBus().interface()->registeredServiceNames().value().contains("org.thesuite.theshell")) {
2017-01-25 11:44:50 +11:00
if (QMessageBox::warning(0, a.translate("main", "theShell already running"), a.translate("main", "theShell seems to already be running. "
2017-01-22 00:08:04 +11:00
"Do you wish to start theShell anyway?"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
return 0;
}
}
2016-08-29 18:51:46 +10:00
QDBusConnection dbus = QDBusConnection::sessionBus();
dbus.registerService("org.thesuite.theshell");
dbusSignals = new DBusSignals();
2016-07-22 22:47:38 +10:00
if (startKscreen) {
QDBusMessage kscreen = QDBusMessage::createMethodCall("org.kde.kded5", "/kded", "org.kde.kded5", "loadModule");
QVariantList args;
args.append("kscreen");
kscreen.setArguments(args);
QDBusConnection::sessionBus().call(kscreen);
}
{
QDBusMessage touchpad = QDBusMessage::createMethodCall("org.kde.kded5", "/kded", "org.kde.kded5", "loadModule");
QVariantList args;
args.append("touchpad");
touchpad.setArguments(args);
QDBusConnection::sessionBus().call(touchpad);
}
{
QDBusMessage sni = QDBusMessage::createMethodCall("org.kde.kded5", "/kded", "org.kde.kded5", "loadModule");
QVariantList args;
args.append("statusnotifierwatcher");
sni.setArguments(args);
QDBusConnection::sessionBus().call(sni);
}
2016-08-29 18:51:46 +10:00
QString windowManager = settings.value("startup/WindowManagerCommand", "kwin_x11").toString();
2016-11-29 22:05:11 +11:00
if (startWm) {
while (!QProcess::startDetached(windowManager)) {
2017-01-25 11:44:50 +11:00
windowManager = QInputDialog::getText(0, a.translate("main", "Window Manager couldn't start"),
a.translate("main", "The window manager \"%1\" could not start. \n\n"
2016-11-29 22:05:11 +11:00
"Enter the name or path of a window manager to attempt to start a different window"
2017-01-22 00:08:04 +11:00
"manager, or hit 'Cancel' to start theShell without a window manager.").arg(windowManager));
2016-11-29 22:05:11 +11:00
if (windowManager == "") {
break;
}
2016-08-29 18:51:46 +10:00
}
}
2016-12-17 23:58:08 +11:00
TutorialWin = new TutorialWindow(tutorialDoSettings);
2017-01-12 01:00:27 +11:00
AudioMan = new AudioManager;
2016-08-29 18:51:46 +10:00
2016-09-26 16:25:04 +10:00
if (!QDBusConnection::sessionBus().interface()->registeredServiceNames().value().contains("org.kde.kdeconnect") && QFile("/usr/lib/kdeconnectd").exists()) {
//Start KDE Connect if it is not running and it is existant on the PC
QProcess::startDetached("/usr/lib/kdeconnectd");
}
2016-08-20 16:26:35 +10:00
QProcess polkitProcess;
polkitProcess.start("/usr/lib/ts-polkitagent");
2016-08-20 16:26:35 +10:00
QProcess btProcess;
btProcess.start("ts-bt");
2016-08-29 18:51:46 +10:00
btProcess.waitForStarted(); //Wait for ts-bt to start so that the Bluetooth toggle will work properly
locationServices = new LocationServices();
2016-06-11 17:07:36 +10:00
NativeFilter = new NativeEventFilter();
a.installNativeEventFilter(NativeFilter);
ndbus = new NotificationDBus();
updbus = new UPowerDBus();
2017-05-02 17:12:21 +10:00
2017-04-24 15:49:10 +10:00
if (settings.value("startup/lastOnboarding", 0) < ONBOARDING_VERSION || startOnboarding) {
2016-11-25 15:24:09 +11:00
Onboarding* onboardingWindow = new Onboarding();
onboardingWindow->showFullScreen();
if (onboardingWindow->exec() == QDialog::Accepted) {
settings.setValue("startup/lastOnboarding", ONBOARDING_VERSION);
} else {
//Log out
return 0;
}
2016-11-25 15:24:09 +11:00
}
2016-08-20 16:26:35 +10:00
MainWin = new MainWindow();
new GlobalFilter(&a);
2016-06-28 16:48:19 +10:00
qDBusRegisterMetaType<QList<QVariantMap>>();
2016-06-24 15:53:02 +10:00
qDBusRegisterMetaType<QMap<QString, QVariantMap>>();
if (autoStart) {
QStringList autostartApps = settings.value("startup/autostart", "").toString().split(",");
for (QString app : autostartApps) {
QProcess::startDetached(app);
}
}
QRect screenGeometry = QApplication::desktop()->screenGeometry();
2016-03-17 19:46:40 +11:00
2016-12-01 12:09:40 +11:00
MainWin->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus);
2016-05-29 17:03:52 +10:00
MainWin->setGeometry(screenGeometry.x() - 1, screenGeometry.y(), screenGeometry.width() + 1, MainWin->height());
MainWin->show();
2016-02-17 17:24:00 +11:00
2017-08-07 18:08:56 +10:00
//QThread::sleep(1);
2016-03-17 19:46:40 +11:00
2016-02-17 17:24:00 +11:00
return a.exec();
}
2016-03-29 17:42:24 +11:00
void playSound(QUrl location, bool uncompressed = false) {
if (uncompressed) {
QSoundEffect* sound = new QSoundEffect();
sound->setSource(location);
sound->play();
} else {
QMediaPlayer* sound = new QMediaPlayer();
sound->setMedia(location);
sound->play();
}
}
2016-05-29 17:03:52 +10:00
QIcon getIconFromTheme(QString name, QColor textColor) {
int averageCol = (textColor.red() + textColor.green() + textColor.blue()) / 3;
if (averageCol <= 127) {
return QIcon(":/icons/dark/images/dark/" + name);
} else {
return QIcon(":/icons/light/images/light/" + name);
}
}
void EndSession(EndSessionWait::shutdownType type) {
switch (type) {
case EndSessionWait::powerOff:
case EndSessionWait::reboot:
case EndSessionWait::logout:
case EndSessionWait::dummy:
{
EndSessionWait* w = new EndSessionWait(type);
w->showFullScreen();
QApplication::setOverrideCursor(Qt::BlankCursor);
}
break;
case EndSessionWait::suspend:
{
QList<QVariant> arguments;
arguments.append(true);
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Suspend");
message.setArguments(arguments);
QDBusConnection::systemBus().send(message);
}
break;
case EndSessionWait::hibernate:
{
QList<QVariant> arguments;
arguments.append(true);
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Hibernate");
message.setArguments(arguments);
QDBusConnection::systemBus().send(message);
}
break;
}
2016-05-29 17:03:52 +10:00
}
QString calculateSize(quint64 size) {
QString ret;
if (size > 1073741824) {
ret = QString::number(((float) size / 1024 / 1024 / 1024), 'f', 2).append(" GiB");
} else if (size > 1048576) {
ret = QString::number(((float) size / 1024 / 1024), 'f', 2).append(" MiB");
} else if (size > 1024) {
ret = QString::number(((float) size / 1024), 'f', 2).append(" KiB");
} else {
ret = QString::number((float) size, 'f', 2).append(" B");
}
return ret;
}
void sendMessageToRootWindow(const char* message, Window window, long data0, long data1, long data2, long data3, long data4) {
XEvent event;
event.xclient.type = ClientMessage;
event.xclient.serial = 0;
event.xclient.send_event = True;
event.xclient.message_type = XInternAtom(QX11Info::display(), message, False);
event.xclient.window = window;
event.xclient.format = 32;
event.xclient.data.l[0] = data0;
event.xclient.data.l[1] = data1;
event.xclient.data.l[2] = data2;
event.xclient.data.l[3] = data3;
event.xclient.data.l[4] = data4;
XSendEvent(QX11Info::display(), DefaultRootWindow(QX11Info::display()), False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
}
2017-04-13 12:17:43 +10:00
float getDPIScaling() {
float currentDPI = QApplication::desktop()->logicalDpiX();
return currentDPI / (float) 96;
}