You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lxqt-session-packaging/lxqt-session/src/sessionapplication.cpp

320 lines
10 KiB

/*
* Copyright (C) 2014 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include "sessionapplication.h"
#include "sessiondbusadaptor.h"
#include "lxqtmodman.h"
#include "UdevNotifier.h"
#include "numlock.h"
#include "lockscreenmanager.h"
#include <unistd.h>
#include <csignal>
#include <LXQt/Settings>
#include <QProcess>
#include "log.h"
#include <QX11Info>
// XKB, this should be disabled in Wayland?
#include <X11/XKBlib.h>
SessionApplication::SessionApplication(int& argc, char** argv) :
LXQt::Application(argc, argv),
lockScreenManager(new LockScreenManager(this))
{
listenToUnixSignals({SIGINT, SIGTERM, SIGQUIT, SIGHUP});
char* winmanager = NULL;
int c;
while ((c = getopt (argc, argv, "c:w:")) != -1)
{
if (c == 'c')
{
configName = optarg;
break;
}
else if (c == 'w')
{
winmanager = optarg;
break;
}
}
if(configName.isEmpty())
configName = "session";
// tell the world which config file we're using.
qputenv("LXQT_SESSION_CONFIG", configName.toUtf8());
modman = new LXQtModuleManager(winmanager);
connect(this, &LXQt::Application::unixSignal, modman, &LXQtModuleManager::logout);
new SessionDBusAdaptor(modman);
// connect to D-Bus and register as an object:
QDBusConnection::sessionBus().registerService("org.lxqt.session");
QDBusConnection::sessionBus().registerObject("/LXQtSession", modman);
// Wait until the event loop starts
QTimer::singleShot(0, this, SLOT(startup()));
}
SessionApplication::~SessionApplication()
{
delete modman;
}
bool SessionApplication::startup()
{
LXQt::Settings settings(configName);
qCDebug(SESSION) << __FILE__ << ":" << __LINE__ << "Session" << configName << "about to launch (default 'session')";
loadEnvironmentSettings(settings);
// loadFontSettings(settings);
loadKeyboardSettings(settings);
loadMouseSettings(settings);
#if defined(WITH_LIBUDEV_MONITOR)
UdevNotifier * dev_notifier = new UdevNotifier{QStringLiteral("input"), this}; //will be released upon our destruction
QTimer * dev_timer = new QTimer{this}; //will be released upon our destruction
dev_timer->setSingleShot(true);
dev_timer->setInterval(500); //give some time to xorg... we need to reset keyboard afterwards
connect(dev_timer, &QTimer::timeout, [this]
{
//XXX: is this a race? (because settings can be currently changed by lxqt-config-input)
// but with such a little probablity we can live...
LXQt::Settings settings(configName);
loadKeyboardSettings(settings);
});
connect(dev_notifier, &UdevNotifier::deviceAdded, [this, dev_timer] (QString device)
{
qCWarning(SESSION) << QStringLiteral("Session '%1', new input device '%2', keyboard setting will be (optionaly) reloaded...").arg(configName).arg(device);
dev_timer->start();
});
#endif
bool lockBeforeSleep = settings.value(QLatin1String("lock_screen_before_power_actions"), true).toBool();
if (lockScreenManager->startup(lockBeforeSleep))
qCDebug(SESSION) << "LockScreenManager started successfully";
else
qCWarning(SESSION) << "LockScreenManager couldn't start";
// launch module manager and autostart apps
modman->startup(settings);
return true;
}
void SessionApplication::mergeXrdb(const char* content, int len)
{
qCDebug(SESSION) << "xrdb:" << content;
QProcess xrdb;
xrdb.start("xrdb -merge -");
xrdb.write(content, len);
xrdb.closeWriteChannel();
xrdb.waitForFinished();
}
void SessionApplication::loadEnvironmentSettings(LXQt::Settings& settings)
{
// first - set some user defined environment variables (like TERM...)
settings.beginGroup("Environment");
QByteArray envVal;
Q_FOREACH (QString i, settings.childKeys())
{
envVal = settings.value(i).toByteArray();
lxqt_setenv(i.toUtf8().constData(), envVal);
}
settings.endGroup();
}
// FIXME: how to set keyboard layout in Wayland?
void SessionApplication::setxkbmap(QString layout, QString variant, QString model, QStringList options) {
QStringList args;
if(!model.isEmpty()) {
args << QStringLiteral("-model");
args << model;
}
if(!layout.isEmpty()) {
args << QStringLiteral("-layout");
args << layout;
if(!variant.isEmpty()) {
args << QStringLiteral("-variant");
args << variant;
}
}
if(!options.isEmpty()) {
Q_FOREACH(const QString& option, options) {
args << QStringLiteral("-option");
args << option;
}
}
// execute the command line
if (!args.isEmpty())
QProcess::startDetached(QStringLiteral("setxkbmap"), args);
}
void SessionApplication::loadKeyboardSettings(LXQt::Settings& settings)
{
qCDebug(SESSION) << settings.fileName();
settings.beginGroup("Keyboard");
XKeyboardControl values;
/* Keyboard settings */
unsigned int delay, interval;
if(XkbGetAutoRepeatRate(QX11Info::display(), XkbUseCoreKbd, (unsigned int*) &delay, (unsigned int*) &interval))
{
delay = settings.value("delay", delay).toUInt();
interval = settings.value("interval", interval).toUInt();
XkbSetAutoRepeatRate(QX11Info::display(), XkbUseCoreKbd, delay, interval);
}
// turn on/off keyboard beep
bool beep = settings.value("beep").toBool();
values.bell_percent = beep ? -1 : 0;
XChangeKeyboardControl(QX11Info::display(), KBBellPercent, &values);
// turn on numlock as needed
if(settings.value("numlock").toBool())
enableNumlock();
// keyboard layout support using setxkbmap
QString layout = settings.value("layout").toString();
QString variant = settings.value("variant").toString();
QString model = settings.value("model").toString();
QStringList options = settings.value("options").toStringList();
setxkbmap(layout, variant, model, options);
settings.endGroup();
}
void SessionApplication::loadMouseSettings(LXQt::Settings& settings)
{
settings.beginGroup("Mouse");
// mouse cursor (does this work?)
QString cursorTheme = settings.value("cursor_theme").toString();
int cursorSize = settings.value("cursor_size").toInt();
QByteArray buf;
if(!cursorTheme.isEmpty()) {
buf += "Xcursor.theme:";
buf += cursorTheme;
buf += '\n';
}
if(cursorSize > 0) {
buf += "Xcursor.size:";
buf += QString("%1").arg(cursorSize);
buf += '\n';
}
if(!buf.isEmpty()) {
buf += "Xcursor.theme_core:true\n";
mergeXrdb(buf.constData(), buf.length());
}
// other mouse settings
int accel_factor = settings.value("accel_factor").toInt();
int accel_threshold = settings.value("accel_threshold").toInt();
if(accel_factor || accel_threshold)
XChangePointerControl(QX11Info::display(), accel_factor != 0, accel_threshold != 0, accel_factor, 10, accel_threshold);
// left handed mouse?
bool left_handed = settings.value("left_handed", false).toBool();
setLeftHandedMouse(left_handed);
settings.endGroup();
}
# if 0
// already deprecated by direct fontconfig support of lxqt-config
void SessionApplication::loadFontSettings(LXQt::Settings& settings)
{
// set some Xft config values, such as antialiasing & subpixel
// may call mergeXrdb() to do it. (will this work?)
// font settings of gtk+ programs are controlled by gtkrc and settings.ini files.
settings.beginGroup("Font");
QByteArray buf;
bool antialias = settings.value("antialias", true).toBool();
buf += "Xft.antialias:";
buf += antialias ? "true" : "false";
buf += '\n';
buf += "Xft.rgba:";
buf += settings.value("subpixel", "none").toByteArray();
buf += '\n';
bool hinting = settings.value("hinting", true).toBool();
buf += "Xft.hinting:";
buf += hinting ? "true" : "false";
buf += '\n';
buf += "Xft.hintstyle:hint";
buf += settings.value("hint_style", "none").toByteArray();
buf += '\n';
int dpi = settings.value("dpi", 96).toInt();
buf += "Xft.dpi:";
buf += QString("%1").arg(dpi);
buf += '\n';
mergeXrdb(buf.constData(), buf.length());
settings.endGroup();
}
#endif
/* This function is taken from Gnome's control-center 2.6.0.3 (gnome-settings-mouse.c) and was modified*/
#define DEFAULT_PTR_MAP_SIZE 128
void SessionApplication::setLeftHandedMouse(bool mouse_left_handed)
{
unsigned char *buttons, *more_buttons;
int n_buttons, i;
int idx_1 = 0, idx_3 = 1;
buttons = (unsigned char*)malloc(DEFAULT_PTR_MAP_SIZE);
if (!buttons)
{
return;
}
n_buttons = XGetPointerMapping(QX11Info::display(), buttons, DEFAULT_PTR_MAP_SIZE);
if (n_buttons > DEFAULT_PTR_MAP_SIZE)
{
more_buttons = (unsigned char*)realloc(buttons, n_buttons);
if (!more_buttons)
{
free(buttons);
return;
}
buttons = more_buttons;
n_buttons = XGetPointerMapping(QX11Info::display(), buttons, n_buttons);
}
for (i = 0; i < n_buttons; i++)
{
if (buttons[i] == 1)
idx_1 = i;
else if (buttons[i] == ((n_buttons < 3) ? 2 : 3))
idx_3 = i;
}
if ((mouse_left_handed && idx_1 < idx_3) ||
(!mouse_left_handed && idx_1 > idx_3))
{
buttons[idx_1] = ((n_buttons < 3) ? 2 : 3);
buttons[idx_3] = 1;
XSetPointerMapping(QX11Info::display(), buttons, n_buttons);
}
free(buttons);
}