[kcmkwin/desktop] KCM using new virtual desktops DBus interface
Summary: A rewrite of the Virtual Desktops KCM using the new DBus API. Depends on D13887. Reviewers: mart, davidedmundson, ltoscano, zzag Subscribers: davidedmundson, broulik, plasma-devel, kwin Tags: #kwin Maniphest Tasks: T4457 Differential Revision: https://phabricator.kde.org/D14542
This commit is contained in:
parent
9993c6d674
commit
cee5ea7819
14 changed files with 1447 additions and 1306 deletions
|
@ -1,33 +1,27 @@
|
||||||
|
include(ECMQMLModules)
|
||||||
|
ecm_find_qmlmodule(org.kde.plasma.core 2.0)
|
||||||
|
|
||||||
|
# KI18N Translation Domain for this library.
|
||||||
|
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwin_virtualdesktops\")
|
||||||
|
|
||||||
########### next target ###############
|
########### next target ###############
|
||||||
# KI18N Translation Domain for this library
|
|
||||||
add_definitions(-DTRANSLATION_DOMAIN=\"kcm_kwindesktop\")
|
|
||||||
|
|
||||||
include_directories(${KWIN_SOURCE_DIR}/effects)
|
set(kcm_kwin_virtualdesktops_PART_SRCS virtualdesktops.cpp desktopsmodel.cpp ../../virtualdesktopsdbustypes.cpp)
|
||||||
|
|
||||||
set(kcm_kwindesktop_PART_SRCS main.cpp desktopnameswidget.cpp)
|
add_library(kcm_kwin_virtualdesktops MODULE ${kcm_kwin_virtualdesktops_PART_SRCS})
|
||||||
ki18n_wrap_ui(kcm_kwindesktop_PART_SRCS main.ui)
|
|
||||||
qt5_add_dbus_interface( kcm_kwindesktop_PART_SRCS
|
|
||||||
${KWIN_SOURCE_DIR}/org.kde.kwin.Effects.xml kwin_effects_interface)
|
|
||||||
|
|
||||||
add_library(kcm_kwindesktop MODULE ${kcm_kwindesktop_PART_SRCS})
|
target_link_libraries(kcm_kwin_virtualdesktops
|
||||||
|
Qt5::DBus
|
||||||
target_link_libraries(kcm_kwindesktop
|
|
||||||
Qt5::X11Extras
|
|
||||||
KF5::KCMUtils
|
|
||||||
KF5::Completion
|
|
||||||
KF5::GlobalAccel
|
|
||||||
KF5::I18n
|
KF5::I18n
|
||||||
KF5::Package
|
KF5::KCMUtils
|
||||||
KF5::WindowSystem
|
KF5::QuickAddons
|
||||||
KF5::XmlGui
|
|
||||||
${X11_LIBRARIES}
|
|
||||||
kwin4_effect_builtins
|
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS kcm_kwindesktop DESTINATION ${PLUGIN_INSTALL_DIR} )
|
kcoreaddons_desktop_to_json(kcm_kwin_virtualdesktops "kcm_kwin_virtualdesktops.desktop")
|
||||||
|
|
||||||
|
|
||||||
########### install files ###############
|
########### install files ###############
|
||||||
install( FILES desktop.desktop DESTINATION ${SERVICES_INSTALL_DIR} )
|
|
||||||
|
install(TARGETS kcm_kwin_virtualdesktops DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
|
||||||
|
install(FILES kcm_kwin_virtualdesktops.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR})
|
||||||
|
kpackage_install_package(package kcm_kwin_virtualdesktops kcms)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
$EXTRACTRC `find . -name \*.ui` >> rc.cpp || exit 11
|
$XGETTEXT `find . -name \*.cpp -o -name \*.qml` -o $podir/kcm_kwin_virtualdesktops.pot
|
||||||
$XGETTEXT *.cpp -o $podir/kcm_kwindesktop.pot
|
|
||||||
rm -f rc.cpp
|
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
/********************************************************************
|
|
||||||
KWin - the KDE window manager
|
|
||||||
This file is part of the KDE project.
|
|
||||||
|
|
||||||
Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org>
|
|
||||||
|
|
||||||
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 2 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/>.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#include "desktopnameswidget.h"
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QGridLayout>
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
#include <KLineEdit>
|
|
||||||
|
|
||||||
namespace KWin
|
|
||||||
{
|
|
||||||
|
|
||||||
DesktopNamesWidget::DesktopNamesWidget(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_maxDesktops(0)
|
|
||||||
, m_desktopConfig(0)
|
|
||||||
{
|
|
||||||
m_namesLayout = new QGridLayout;
|
|
||||||
m_namesLayout->setMargin(0);
|
|
||||||
|
|
||||||
setLayout(m_namesLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
DesktopNamesWidget::~DesktopNamesWidget()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesktopNamesWidget::numberChanged(int number)
|
|
||||||
{
|
|
||||||
if ((number < 1) || (number > m_maxDesktops))
|
|
||||||
return;
|
|
||||||
if (m_nameInputs.size() != number) {
|
|
||||||
if (number < m_nameInputs.size()) {
|
|
||||||
// remove widgets
|
|
||||||
while (number != m_nameInputs.size()) {
|
|
||||||
KLineEdit* edit = m_nameInputs.last();
|
|
||||||
m_nameInputs.removeLast();
|
|
||||||
delete edit;
|
|
||||||
QLabel* label = m_nameLabels.last();
|
|
||||||
m_nameLabels.removeLast();
|
|
||||||
delete label;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// add widgets
|
|
||||||
while (number != m_nameInputs.size()) {
|
|
||||||
int desktop = m_nameInputs.size();
|
|
||||||
QLabel* label = new QLabel(i18n("Desktop %1:", desktop + 1), this);
|
|
||||||
KLineEdit* edit = new KLineEdit(this);
|
|
||||||
label->setWhatsThis(i18n("Here you can enter the name for desktop %1", desktop + 1));
|
|
||||||
edit->setWhatsThis(i18n("Here you can enter the name for desktop %1", desktop + 1));
|
|
||||||
|
|
||||||
m_namesLayout->addWidget(label, desktop % 10, 0 + 2 *(desktop >= 10), 1, 1);
|
|
||||||
m_namesLayout->addWidget(edit, desktop % 10, 1 + 2 *(desktop >= 10), 1, 1);
|
|
||||||
m_nameInputs << edit;
|
|
||||||
m_nameLabels << label;
|
|
||||||
|
|
||||||
setDefaultName(desktop + 1);
|
|
||||||
if (desktop > 1) {
|
|
||||||
setTabOrder(m_nameInputs[desktop - 1], m_nameInputs[desktop]);
|
|
||||||
}
|
|
||||||
connect(edit, SIGNAL(textChanged(QString)), SIGNAL(changed()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DesktopNamesWidget::name(int desktop)
|
|
||||||
{
|
|
||||||
if ((desktop < 1) || (desktop > m_maxDesktops) || (desktop > m_nameInputs.size()))
|
|
||||||
return QString();
|
|
||||||
return m_nameInputs[ desktop -1 ]->text();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DesktopNamesWidget::setName(int desktop, QString desktopName)
|
|
||||||
{
|
|
||||||
if ((desktop < 1) || (desktop > m_maxDesktops) || (desktop > m_nameInputs.size()))
|
|
||||||
return;
|
|
||||||
m_nameInputs[ desktop-1 ]->setText(desktopName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesktopNamesWidget::setDefaultName(int desktop)
|
|
||||||
{
|
|
||||||
if ((desktop < 1) || (desktop > m_maxDesktops))
|
|
||||||
return;
|
|
||||||
QString name = m_desktopConfig->cachedDesktopName(desktop);
|
|
||||||
if (name.isEmpty())
|
|
||||||
name = i18n("Desktop %1", desktop);
|
|
||||||
m_nameInputs[ desktop -1 ]->setText(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void DesktopNamesWidget::setMaxDesktops(int maxDesktops)
|
|
||||||
{
|
|
||||||
m_maxDesktops = maxDesktops;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DesktopNamesWidget::setDesktopConfig(KWinDesktopConfig* desktopConfig)
|
|
||||||
{
|
|
||||||
m_desktopConfig = desktopConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
/********************************************************************
|
|
||||||
KWin - the KDE window manager
|
|
||||||
This file is part of the KDE project.
|
|
||||||
|
|
||||||
Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org>
|
|
||||||
|
|
||||||
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 2 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/>.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#ifndef DESKTOPNAMESWIDGET_H
|
|
||||||
#define DESKTOPNAMESWIDGET_H
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class KLineEdit;
|
|
||||||
class QLabel;
|
|
||||||
class QGridLayout;
|
|
||||||
|
|
||||||
namespace KWin
|
|
||||||
{
|
|
||||||
class KWinDesktopConfig;
|
|
||||||
|
|
||||||
class DesktopNamesWidget : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit DesktopNamesWidget(QWidget *parent);
|
|
||||||
~DesktopNamesWidget();
|
|
||||||
QString name(int desktop);
|
|
||||||
void setName(int desktop, QString desktopName);
|
|
||||||
void setDefaultName(int desktop);
|
|
||||||
void setMaxDesktops(int maxDesktops);
|
|
||||||
void setDesktopConfig(KWinDesktopConfig *desktopConfig);
|
|
||||||
|
|
||||||
Q_SIGNALS:
|
|
||||||
void changed();
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
void numberChanged(int number);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QList< QLabel* > m_nameLabels;
|
|
||||||
QList< KLineEdit* > m_nameInputs;
|
|
||||||
QGridLayout* m_namesLayout;
|
|
||||||
int m_maxDesktops;
|
|
||||||
KWinDesktopConfig *m_desktopConfig;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#endif // DESKTOPNAMESWIDGET_H
|
|
637
kcmkwin/kwindesktop/desktopsmodel.cpp
Normal file
637
kcmkwin/kwindesktop/desktopsmodel.cpp
Normal file
|
@ -0,0 +1,637 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Eike Hein <hein@kde.org>
|
||||||
|
* Copyright (C) 2018 Marco Martin <mart@kde.org>
|
||||||
|
*
|
||||||
|
* 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 2 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "desktopsmodel.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
#include <QDBusArgument>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusMessage>
|
||||||
|
#include <QDBusMetaType>
|
||||||
|
#include <QDBusPendingCall>
|
||||||
|
#include <QDBusPendingCallWatcher>
|
||||||
|
#include <QDBusPendingReply>
|
||||||
|
#include <QDBusServiceWatcher>
|
||||||
|
#include <QDBusVariant>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
#include <QUuid>
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
static const QString s_serviceName(QStringLiteral("org.kde.KWin"));
|
||||||
|
static const QString s_virtualDesktopsInterface(QStringLiteral("org.kde.KWin.VirtualDesktopManager"));
|
||||||
|
static const QString s_virtDesktopsPath(QStringLiteral("/VirtualDesktopManager"));
|
||||||
|
static const QString s_fdoPropertiesInterface(QStringLiteral("org.freedesktop.DBus.Properties"));
|
||||||
|
|
||||||
|
DesktopsModel::DesktopsModel(QObject *parent)
|
||||||
|
: QAbstractListModel(parent)
|
||||||
|
, m_userModified(false)
|
||||||
|
, m_serverModified(false)
|
||||||
|
, m_serverSideRows(-1)
|
||||||
|
, m_rows(-1)
|
||||||
|
, m_synchronizing(false)
|
||||||
|
{
|
||||||
|
qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>();
|
||||||
|
qDBusRegisterMetaType<KWin::DBusDesktopDataVector>();
|
||||||
|
|
||||||
|
m_serviceWatcher = new QDBusServiceWatcher(s_serviceName,
|
||||||
|
QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForOwnerChange);
|
||||||
|
|
||||||
|
QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceRegistered,
|
||||||
|
this, [this]() { reset(); });
|
||||||
|
|
||||||
|
QObject::connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered,
|
||||||
|
this, [this]() {
|
||||||
|
QDBusConnection::sessionBus().disconnect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopCreated"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopCreated(QString,KWin::DBusDesktopDataStruct)));
|
||||||
|
|
||||||
|
QDBusConnection::sessionBus().disconnect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopRemoved"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopRemoved(QString)));
|
||||||
|
|
||||||
|
QDBusConnection::sessionBus().disconnect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopDataChanged"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopDataChanged(QString,KWin::DBusDesktopDataStruct)));
|
||||||
|
|
||||||
|
|
||||||
|
QDBusConnection::sessionBus().disconnect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("rowsChanged"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopRowsChanged(uint)));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
DesktopsModel::~DesktopsModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> DesktopsModel::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||||
|
|
||||||
|
QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles"));
|
||||||
|
|
||||||
|
for (int i = 0; i < e.keyCount(); ++i) {
|
||||||
|
roles.insert(e.value(i), e.key(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DesktopsModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid() || index.row() < 0 || index.row() > (m_desktops.count() - 1)) {
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
return m_names.value(m_desktops.at(index.row()));
|
||||||
|
} else if (role == Id) {
|
||||||
|
return m_desktops.at(index.row());
|
||||||
|
} else if (role == DesktopRow) {
|
||||||
|
const int rows = std::max(m_rows, 1);
|
||||||
|
const int perRow = std::ceil((qreal)m_desktops.count() / (qreal)rows);
|
||||||
|
|
||||||
|
return (index.row() / perRow) + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesktopsModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_desktops.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopsModel::ready() const
|
||||||
|
{
|
||||||
|
return !m_desktops.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DesktopsModel::error() const
|
||||||
|
{
|
||||||
|
return m_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopsModel::userModified() const
|
||||||
|
{
|
||||||
|
return m_userModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopsModel::serverModified() const
|
||||||
|
{
|
||||||
|
return m_serverModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DesktopsModel::rows() const
|
||||||
|
{
|
||||||
|
return m_rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::setRows(int rows)
|
||||||
|
{
|
||||||
|
if (!ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_rows != rows) {
|
||||||
|
m_rows = rows;
|
||||||
|
|
||||||
|
emit rowsChanged();
|
||||||
|
emit dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QVector<int>{DesktopRow});
|
||||||
|
|
||||||
|
updateModifiedState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::createDesktop(const QString &name)
|
||||||
|
{
|
||||||
|
if (!ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
beginInsertRows(QModelIndex(), m_desktops.count(), m_desktops.count());
|
||||||
|
|
||||||
|
const QString &dummyId = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||||
|
|
||||||
|
m_desktops.append(dummyId);
|
||||||
|
m_names[dummyId] = name;
|
||||||
|
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
updateModifiedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::removeDesktop(const QString &id)
|
||||||
|
{
|
||||||
|
if (!ready() || !m_desktops.contains(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int desktopIndex = m_desktops.indexOf(id);
|
||||||
|
|
||||||
|
beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex);
|
||||||
|
|
||||||
|
m_desktops.removeAt(desktopIndex);
|
||||||
|
m_names.remove(id);
|
||||||
|
|
||||||
|
endRemoveRows();
|
||||||
|
|
||||||
|
updateModifiedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::setDesktopName(const QString &id, const QString &name)
|
||||||
|
{
|
||||||
|
if (!ready() || !m_desktops.contains(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_names[id] = name;
|
||||||
|
|
||||||
|
const QModelIndex &idx = index(m_desktops.indexOf(id), 0);
|
||||||
|
|
||||||
|
dataChanged(idx, idx, QVector<int>{Qt::DisplayRole});
|
||||||
|
|
||||||
|
updateModifiedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::syncWithServer()
|
||||||
|
{
|
||||||
|
m_synchronizing = true;
|
||||||
|
|
||||||
|
auto callFinished = [this](QDBusPendingCallWatcher *call) {
|
||||||
|
QDBusPendingReply<void> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
handleCallError();
|
||||||
|
}
|
||||||
|
|
||||||
|
call->deleteLater();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_desktops.count() > m_serverSideDesktops.count()) {
|
||||||
|
auto call = QDBusMessage::createMethodCall(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("createDesktop"));
|
||||||
|
|
||||||
|
const int newIndex = m_serverSideDesktops.count();
|
||||||
|
|
||||||
|
call.setArguments({(uint)newIndex, m_names.value(m_desktops.at(newIndex))});
|
||||||
|
|
||||||
|
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
|
||||||
|
|
||||||
|
const auto *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
|
||||||
|
|
||||||
|
return; // The change-handling slot will call syncWithServer() again,
|
||||||
|
// until everything is in sync.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_desktops.count() < m_serverSideDesktops.count()) {
|
||||||
|
QStringListIterator i(m_serverSideDesktops);
|
||||||
|
|
||||||
|
i.toBack();
|
||||||
|
|
||||||
|
while (i.hasPrevious()) {
|
||||||
|
const QString &previous = i.previous();
|
||||||
|
|
||||||
|
if (!m_desktops.contains(previous)) {
|
||||||
|
auto call = QDBusMessage::createMethodCall(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("removeDesktop"));
|
||||||
|
|
||||||
|
call.setArguments({previous});
|
||||||
|
|
||||||
|
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
|
||||||
|
|
||||||
|
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
|
||||||
|
|
||||||
|
return; // The change-handling slot will call syncWithServer() again,
|
||||||
|
// until everything is in sync.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync ids. Replace dummy ids in the process.
|
||||||
|
for (int i = 0; i < m_serverSideDesktops.count(); ++i) {
|
||||||
|
const QString oldId = m_desktops.at(i);
|
||||||
|
const QString &newId = m_serverSideDesktops.at(i);
|
||||||
|
m_desktops[i] = newId;
|
||||||
|
m_names[newId] = m_names.take(oldId);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>{Qt::DisplayRole});
|
||||||
|
|
||||||
|
// Sync names.
|
||||||
|
if (m_names != m_serverSideNames) {
|
||||||
|
QHashIterator<QString, QString> i(m_names);
|
||||||
|
|
||||||
|
while (i.hasNext()) {
|
||||||
|
i.next();
|
||||||
|
|
||||||
|
if (i.value() != m_serverSideNames.value(i.key())) {
|
||||||
|
auto call = QDBusMessage::createMethodCall(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("setDesktopName"));
|
||||||
|
|
||||||
|
call.setArguments({i.key(), i.value()});
|
||||||
|
|
||||||
|
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
|
||||||
|
|
||||||
|
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return; // The change-handling slot will call syncWithServer() again,
|
||||||
|
// until everything is in sync..
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync rows.
|
||||||
|
if (m_rows != m_serverSideRows) {
|
||||||
|
auto call = QDBusMessage::createMethodCall(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_fdoPropertiesInterface,
|
||||||
|
QStringLiteral("Set"));
|
||||||
|
|
||||||
|
call.setArguments({s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("rows"), QVariant::fromValue(QDBusVariant(QVariant((uint)m_rows)))});
|
||||||
|
|
||||||
|
QDBusPendingCall pending = QDBusConnection::sessionBus().asyncCall(call);
|
||||||
|
|
||||||
|
const QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending, this);
|
||||||
|
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, callFinished);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::reset()
|
||||||
|
{
|
||||||
|
m_synchronizing = false; // Sanity.
|
||||||
|
|
||||||
|
auto getAllAndConnectCall = QDBusMessage::createMethodCall(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_fdoPropertiesInterface,
|
||||||
|
QStringLiteral("GetAll"));
|
||||||
|
|
||||||
|
getAllAndConnectCall.setArguments({s_virtualDesktopsInterface});
|
||||||
|
|
||||||
|
QDBusConnection::sessionBus().callWithCallback(
|
||||||
|
getAllAndConnectCall,
|
||||||
|
this,
|
||||||
|
SLOT(getAllAndConnect(QDBusMessage)),
|
||||||
|
SLOT(handleCallError()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::getAllAndConnect(const QDBusMessage &msg)
|
||||||
|
{
|
||||||
|
const QVariantMap &data = qdbus_cast<QVariantMap>(msg.arguments().at(0).value<QDBusArgument>());
|
||||||
|
|
||||||
|
const KWin::DBusDesktopDataVector &desktops = qdbus_cast<KWin::DBusDesktopDataVector>(
|
||||||
|
data.value(QStringLiteral("desktops")).value<QDBusArgument>()
|
||||||
|
);
|
||||||
|
|
||||||
|
const int newServerSideRows = data.value(QStringLiteral("rows")).toUInt();
|
||||||
|
QStringList newServerSideDesktops;
|
||||||
|
QHash<QString,QString> newServerSideNames;
|
||||||
|
|
||||||
|
for (const KWin::DBusDesktopDataStruct &d : desktops) {
|
||||||
|
newServerSideDesktops.append(d.id);
|
||||||
|
newServerSideNames[d.id] = d.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the server-side state changed during a KWin restart, and the
|
||||||
|
// user had made notifications, the model should notify about the
|
||||||
|
// change.
|
||||||
|
if (m_serverSideDesktops != newServerSideDesktops
|
||||||
|
|| m_serverSideNames != newServerSideNames
|
||||||
|
|| m_serverSideRows != newServerSideRows) {
|
||||||
|
if (!m_serverSideDesktops.isEmpty() || m_userModified) {
|
||||||
|
m_serverModified = true;
|
||||||
|
emit serverModifiedChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_serverSideDesktops = newServerSideDesktops;
|
||||||
|
m_serverSideNames = newServerSideNames;
|
||||||
|
m_serverSideRows = newServerSideRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the case KWin restarts while the KCM was open: If the user had
|
||||||
|
// made no modifications, just reset to the server data. E.g. perhaps
|
||||||
|
// the user intentionally nuked the KWin config while it was down, so
|
||||||
|
// we should follow.
|
||||||
|
if (!m_userModified || m_desktops.empty()) {
|
||||||
|
beginResetModel();
|
||||||
|
m_desktops = m_serverSideDesktops;
|
||||||
|
m_names = m_serverSideNames;
|
||||||
|
m_rows = m_serverSideRows;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit readyChanged();
|
||||||
|
|
||||||
|
auto handleConnectionError = [this]() {
|
||||||
|
m_error = i18n("There was an error connecting to the compositor.");
|
||||||
|
emit errorChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
bool connected = QDBusConnection::sessionBus().connect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopCreated"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopCreated(QString,KWin::DBusDesktopDataStruct)));
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
handleConnectionError();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connected = QDBusConnection::sessionBus().connect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopRemoved"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopRemoved(QString)));
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
handleConnectionError();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connected = QDBusConnection::sessionBus().connect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("desktopDataChanged"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopDataChanged(QString,KWin::DBusDesktopDataStruct)));
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
handleConnectionError();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connected = QDBusConnection::sessionBus().connect(
|
||||||
|
s_serviceName,
|
||||||
|
s_virtDesktopsPath,
|
||||||
|
s_virtualDesktopsInterface,
|
||||||
|
QStringLiteral("rowsChanged"),
|
||||||
|
this,
|
||||||
|
SLOT(desktopRowsChanged(uint)));
|
||||||
|
|
||||||
|
if (!connected) {
|
||||||
|
handleConnectionError();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::desktopCreated(const QString &id, const KWin::DBusDesktopDataStruct &data)
|
||||||
|
{
|
||||||
|
m_serverSideDesktops.insert(data.position, id);
|
||||||
|
m_serverSideNames[data.id] = data.name;
|
||||||
|
|
||||||
|
// If the user didn't make any changes, we can just stay in sync.
|
||||||
|
if (!m_userModified) {
|
||||||
|
beginInsertRows(QModelIndex(), data.position, data.position);
|
||||||
|
|
||||||
|
m_desktops = m_serverSideDesktops;
|
||||||
|
m_names = m_serverSideNames;
|
||||||
|
|
||||||
|
endInsertRows();
|
||||||
|
} else {
|
||||||
|
// Remove dummy data.
|
||||||
|
const QString dummyId = m_desktops.at(data.position);
|
||||||
|
m_desktops[data.position] = id;
|
||||||
|
m_names.remove(dummyId);
|
||||||
|
m_names[id] = data.name;
|
||||||
|
const QModelIndex &idx = index(data.position, 0);
|
||||||
|
emit dataChanged(idx, idx, QVector<int>{Id});
|
||||||
|
|
||||||
|
updateModifiedState(/* server */ true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::desktopRemoved(const QString &id)
|
||||||
|
{
|
||||||
|
const int desktopIndex = m_serverSideDesktops.indexOf(id);
|
||||||
|
|
||||||
|
m_serverSideDesktops.removeAt(desktopIndex);
|
||||||
|
m_serverSideNames.remove(id);
|
||||||
|
|
||||||
|
// If the user didn't make any changes, we can just stay in sync.
|
||||||
|
if (!m_userModified) {
|
||||||
|
beginRemoveRows(QModelIndex(), desktopIndex, desktopIndex);
|
||||||
|
|
||||||
|
m_desktops = m_serverSideDesktops;
|
||||||
|
m_names = m_serverSideNames;
|
||||||
|
|
||||||
|
endRemoveRows();
|
||||||
|
} else {
|
||||||
|
updateModifiedState(/* server */ true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::desktopDataChanged(const QString &id, const KWin::DBusDesktopDataStruct &data)
|
||||||
|
{
|
||||||
|
const int desktopIndex = m_serverSideDesktops.indexOf(id);
|
||||||
|
|
||||||
|
m_serverSideDesktops[desktopIndex] = id;
|
||||||
|
m_serverSideNames[id] = data.name;
|
||||||
|
|
||||||
|
// If the user didn't make any changes, we can just stay in sync.
|
||||||
|
if (!m_userModified) {
|
||||||
|
m_desktops = m_serverSideDesktops;
|
||||||
|
m_names = m_serverSideNames;
|
||||||
|
|
||||||
|
const QModelIndex &idx = index(desktopIndex, 0);
|
||||||
|
|
||||||
|
dataChanged(idx, idx, QVector<int>{Qt::DisplayRole});
|
||||||
|
} else {
|
||||||
|
updateModifiedState(/* server */ true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::desktopRowsChanged(uint rows)
|
||||||
|
{
|
||||||
|
// Unfortunately we sometimes get this signal from the server with an unchanged value.
|
||||||
|
if ((int)rows == m_serverSideRows) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_serverSideRows = rows;
|
||||||
|
|
||||||
|
// If the user didn't make any changes, we can just stay in sync.
|
||||||
|
if (!m_userModified) {
|
||||||
|
m_rows = m_serverSideRows;
|
||||||
|
|
||||||
|
emit rowsChanged();
|
||||||
|
emit dataChanged(index(0, 0), index(m_desktops.count() - 1, 0), QVector<int>{DesktopRow});
|
||||||
|
} else {
|
||||||
|
updateModifiedState(/* server */ true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::updateModifiedState(bool server)
|
||||||
|
{
|
||||||
|
// Count is the same but contents are not: The user may have
|
||||||
|
// removed and created new desktops in the UI, but there were
|
||||||
|
// no changes to send to the server because number and names
|
||||||
|
// have remained the same. In that case we can just clean
|
||||||
|
// that up here.
|
||||||
|
if (m_desktops.count() == m_serverSideDesktops.count()
|
||||||
|
&& m_desktops != m_serverSideDesktops) {
|
||||||
|
|
||||||
|
for (int i = 0; i < m_serverSideDesktops.count(); ++i) {
|
||||||
|
const QString oldId = m_desktops.at(i);
|
||||||
|
const QString &newId = m_serverSideDesktops.at(i);
|
||||||
|
m_desktops[i] = newId;
|
||||||
|
m_names[newId] = m_names.take(oldId);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>{Qt::DisplayRole});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_desktops == m_serverSideDesktops
|
||||||
|
&& m_names == m_serverSideNames
|
||||||
|
&& m_rows == m_serverSideRows) {
|
||||||
|
|
||||||
|
m_userModified = false;
|
||||||
|
emit userModifiedChanged();
|
||||||
|
|
||||||
|
m_serverModified = false;
|
||||||
|
emit serverModifiedChanged();
|
||||||
|
|
||||||
|
m_synchronizing = false;
|
||||||
|
} else {
|
||||||
|
if (m_synchronizing) {
|
||||||
|
m_serverModified = false;
|
||||||
|
emit serverModifiedChanged();
|
||||||
|
|
||||||
|
syncWithServer();
|
||||||
|
} else if (server) {
|
||||||
|
m_serverModified = true;
|
||||||
|
emit serverModifiedChanged();
|
||||||
|
} else {
|
||||||
|
m_userModified = true;
|
||||||
|
emit userModifiedChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopsModel::handleCallError()
|
||||||
|
{
|
||||||
|
if (m_synchronizing) {
|
||||||
|
m_synchronizing = false;
|
||||||
|
|
||||||
|
m_serverModified = false;
|
||||||
|
emit serverModifiedChanged();
|
||||||
|
|
||||||
|
m_error = i18n("There was an error saving the settings to the compositor.");
|
||||||
|
emit errorChanged();
|
||||||
|
} else {
|
||||||
|
m_error = i18n("There was an error requesting information from the compositor.");
|
||||||
|
emit errorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
129
kcmkwin/kwindesktop/desktopsmodel.h
Normal file
129
kcmkwin/kwindesktop/desktopsmodel.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Eike Hein <hein@kde.org>
|
||||||
|
* Copyright (C) 2018 Marco Martin <mart@kde.org>
|
||||||
|
*
|
||||||
|
* 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 2 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DESKTOPSMODEL_H
|
||||||
|
#define DESKTOPSMODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
#include "../virtualdesktopsdbustypes.h"
|
||||||
|
|
||||||
|
class QDBusArgument;
|
||||||
|
class QDBusMessage;
|
||||||
|
class QDBusServiceWatcher;
|
||||||
|
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @short An item model around KWin's D-Bus API for virtual desktops.
|
||||||
|
*
|
||||||
|
* The model initially gets the state from KWin and populates.
|
||||||
|
*
|
||||||
|
* As long as the user makes no changes, KWin-side changes are directly
|
||||||
|
* exposed in the model.
|
||||||
|
*
|
||||||
|
* If the user makes changes (see the `userModified` property), it stops
|
||||||
|
* exposing KWin-side changes live, but it keeps track of the KWin-side
|
||||||
|
* changes, so it can figure out and apply the delta when `syncWithServer`
|
||||||
|
* is called.
|
||||||
|
*
|
||||||
|
* When KWin-side changes happen while the model is user-modified, the
|
||||||
|
* model signals this via the `serverModified` property. A call to
|
||||||
|
* `syncWithServer` will overwrite the KWin-side changes.
|
||||||
|
*
|
||||||
|
* After synchronization, the model tracks Kwin-side changes again,
|
||||||
|
* until the user makes further changes.
|
||||||
|
*
|
||||||
|
* @author Eike Hein <hein@kde.org>
|
||||||
|
**/
|
||||||
|
|
||||||
|
class DesktopsModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool ready READ ready NOTIFY readyChanged)
|
||||||
|
Q_PROPERTY(QString error READ error NOTIFY errorChanged)
|
||||||
|
Q_PROPERTY(bool userModified READ userModified NOTIFY userModifiedChanged)
|
||||||
|
Q_PROPERTY(bool serverModified READ serverModified NOTIFY serverModifiedChanged)
|
||||||
|
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum AdditionalRoles {
|
||||||
|
Id = Qt::UserRole + 1,
|
||||||
|
DesktopRow
|
||||||
|
};
|
||||||
|
Q_ENUM(AdditionalRoles)
|
||||||
|
|
||||||
|
explicit DesktopsModel(QObject *parent = nullptr);
|
||||||
|
~DesktopsModel() override;
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
int rowCount(const QModelIndex &parent = {}) const override;
|
||||||
|
|
||||||
|
bool ready() const;
|
||||||
|
QString error() const;
|
||||||
|
|
||||||
|
bool userModified() const;
|
||||||
|
bool serverModified() const;
|
||||||
|
|
||||||
|
int rows() const;
|
||||||
|
void setRows(int rows);
|
||||||
|
|
||||||
|
Q_INVOKABLE void createDesktop(const QString &name);
|
||||||
|
Q_INVOKABLE void removeDesktop(const QString &id);
|
||||||
|
Q_INVOKABLE void setDesktopName(const QString &id, const QString &name);
|
||||||
|
|
||||||
|
Q_INVOKABLE void syncWithServer();
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void readyChanged() const;
|
||||||
|
void errorChanged() const;
|
||||||
|
void userModifiedChanged() const;
|
||||||
|
void serverModifiedChanged() const;
|
||||||
|
void rowsChanged() const;
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void reset();
|
||||||
|
void getAllAndConnect(const QDBusMessage &msg);
|
||||||
|
void desktopCreated(const QString &id, const KWin::DBusDesktopDataStruct &data);
|
||||||
|
void desktopRemoved(const QString &id);
|
||||||
|
void desktopDataChanged(const QString &id, const KWin::DBusDesktopDataStruct &data);
|
||||||
|
void desktopRowsChanged(uint rows);
|
||||||
|
void updateModifiedState(bool server = false);
|
||||||
|
void handleCallError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QDBusServiceWatcher *m_serviceWatcher;
|
||||||
|
QString m_error;
|
||||||
|
bool m_userModified;
|
||||||
|
bool m_serverModified;
|
||||||
|
QStringList m_serverSideDesktops;
|
||||||
|
QHash<QString,QString> m_serverSideNames;
|
||||||
|
int m_serverSideRows;
|
||||||
|
QStringList m_desktops;
|
||||||
|
QHash<QString,QString> m_names;
|
||||||
|
int m_rows;
|
||||||
|
bool m_synchronizing;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,11 +1,11 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
|
Exec=kcmshell5 kcm_kwin_virtualdesktops
|
||||||
|
Icon=preferences-desktop
|
||||||
Type=Service
|
Type=Service
|
||||||
X-KDE-ServiceTypes=KCModule
|
X-KDE-ServiceTypes=KCModule
|
||||||
X-DocPath=kcontrol/desktop/index.html
|
X-DocPath=kcontrol/kwin_virtualdesktops/index.html
|
||||||
Icon=preferences-desktop
|
|
||||||
Exec=kcmshell5 desktop
|
|
||||||
|
|
||||||
X-KDE-Library=kcm_kwindesktop
|
X-KDE-Library=kcm_kwin_virtualdesktops
|
||||||
X-KDE-ParentApp=kcontrol
|
X-KDE-ParentApp=kcontrol
|
||||||
|
|
||||||
X-KDE-System-Settings-Parent-Category=desktopbehavior
|
X-KDE-System-Settings-Parent-Category=desktopbehavior
|
||||||
|
@ -143,7 +143,7 @@ X-KDE-Keywords[nds]=Schriefdisch,Schriefdischen,virtuell,mehr,Schriefdisch-Över
|
||||||
X-KDE-Keywords[nl]=bureaublad,bureaubladen,aantal,virtueel bureaublad,meervoudige bureaubladen,pager,pager-widget,pager-applet,pagerinstellingen
|
X-KDE-Keywords[nl]=bureaublad,bureaubladen,aantal,virtueel bureaublad,meervoudige bureaubladen,pager,pager-widget,pager-applet,pagerinstellingen
|
||||||
X-KDE-Keywords[nn]=skrivebord,mengd,tal,virtuelt skrivebord,fleire skrivebord,vekslar,vekslarelement,vekslarelement,vekslerinnstillinger,vekslaroppsett
|
X-KDE-Keywords[nn]=skrivebord,mengd,tal,virtuelt skrivebord,fleire skrivebord,vekslar,vekslarelement,vekslarelement,vekslerinnstillinger,vekslaroppsett
|
||||||
X-KDE-Keywords[pa]=ਡੈਸਕਟਾਪ,ਗਿਣਤੀ,ਨੰਬਰ,ਅੰਕ,ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ,ਕਈ ਡੈਸਕਟਾਪ,ਪੇਜ਼ਰ,ਪੇਜ਼ਰ ਵਿਜੈਟ,ਪੇਜ਼ਰ ਐਪਲਿਟ,ਪੇਜ਼ਰ ਸੈਟਿੰਗਾਂ
|
X-KDE-Keywords[pa]=ਡੈਸਕਟਾਪ,ਗਿਣਤੀ,ਨੰਬਰ,ਅੰਕ,ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ,ਕਈ ਡੈਸਕਟਾਪ,ਪੇਜ਼ਰ,ਪੇਜ਼ਰ ਵਿਜੈਟ,ਪੇਜ਼ਰ ਐਪਲਿਟ,ਪੇਜ਼ਰ ਸੈਟਿੰਗਾਂ
|
||||||
X-KDE-Keywords[pl]=pulpit,pulpity,liczba,pulpity wirtualne,wiele pulpitów
|
X-KDE-Keywords[pl]=pulpit,pulpity,liczba,pulpity wirtualne,wiele pulpitów
|
||||||
X-KDE-Keywords[pt]=ecrã,ecrãs,número,ecrã virtual,múltiplos ecrãs,paginador,elemento paginador,'applet' do paginador,configuração do paginador
|
X-KDE-Keywords[pt]=ecrã,ecrãs,número,ecrã virtual,múltiplos ecrãs,paginador,elemento paginador,'applet' do paginador,configuração do paginador
|
||||||
X-KDE-Keywords[pt_BR]=área de trabalho,áreas de trabalho,desktop,desktops,número,área de trabalho virtual,múltiplas áreas de trabalho,paginador,elemento paginador,miniaplicativo do paginador,configurações do paginador
|
X-KDE-Keywords[pt_BR]=área de trabalho,áreas de trabalho,desktop,desktops,número,área de trabalho virtual,múltiplas áreas de trabalho,paginador,elemento paginador,miniaplicativo do paginador,configurações do paginador
|
||||||
X-KDE-Keywords[ru]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,рабочий стол,рабочие столы,число,виртуальный рабочий стол,несколько рабочих столов,переключатель,переключение,виджет переключения,аплет переключения,параметры переключения,настройки переключения
|
X-KDE-Keywords[ru]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,рабочий стол,рабочие столы,число,виртуальный рабочий стол,несколько рабочих столов,переключатель,переключение,виджет переключения,аплет переключения,параметры переключения,настройки переключения
|
||||||
|
@ -159,3 +159,6 @@ X-KDE-Keywords[uk]=desktop,desktops,number,virtual desktop,multiple desktops,pag
|
||||||
X-KDE-Keywords[x-test]=xxdesktopxx,xxdesktopsxx,xxnumberxx,xxvirtual desktopxx,xxmultiple desktopsxx,xxpagerxx,xxpager widgetxx,xxpager appletxx,xxpager settingsxx
|
X-KDE-Keywords[x-test]=xxdesktopxx,xxdesktopsxx,xxnumberxx,xxvirtual desktopxx,xxmultiple desktopsxx,xxpagerxx,xxpager widgetxx,xxpager appletxx,xxpager settingsxx
|
||||||
X-KDE-Keywords[zh_CN]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,桌面,虚拟桌面,多桌面,分页,分页器,分页器组件,分页器设置
|
X-KDE-Keywords[zh_CN]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings,桌面,虚拟桌面,多桌面,分页,分页器,分页器组件,分页器设置
|
||||||
X-KDE-Keywords[zh_TW]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings
|
X-KDE-Keywords[zh_TW]=desktop,desktops,number,virtual desktop,multiple desktops,pager,pager widget,pager applet,pager settings
|
||||||
|
|
||||||
|
|
||||||
|
Categories=Qt;KDE;X-KDE-settings-translations;
|
|
@ -1,671 +0,0 @@
|
||||||
/********************************************************************
|
|
||||||
KWin - the KDE window manager
|
|
||||||
This file is part of the KDE project.
|
|
||||||
|
|
||||||
Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org>
|
|
||||||
|
|
||||||
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 2 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/>.
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include <effect_builtins.h>
|
|
||||||
#include <config-kwin.h>
|
|
||||||
#include <kwin_effects_interface.h>
|
|
||||||
|
|
||||||
#include <QDBusMessage>
|
|
||||||
#include <QDBusConnection>
|
|
||||||
#include <QDBusInterface>
|
|
||||||
|
|
||||||
#include <KAboutData>
|
|
||||||
#include <KAboutApplicationDialog>
|
|
||||||
#include <KActionCollection>
|
|
||||||
#include <KCModuleProxy>
|
|
||||||
#include <KGlobalAccel>
|
|
||||||
#include <KLocalizedString>
|
|
||||||
#include <KPackage/Package>
|
|
||||||
#include <KPackage/PackageLoader>
|
|
||||||
#include <KPluginInfo>
|
|
||||||
#include <KPluginFactory>
|
|
||||||
#include <KPluginTrader>
|
|
||||||
#include <KConfigGroup>
|
|
||||||
#include <KService>
|
|
||||||
#include <KServiceTypeTrader>
|
|
||||||
#include <KShortcutsEditor>
|
|
||||||
|
|
||||||
#include <QX11Info>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <fixx11h.h>
|
|
||||||
|
|
||||||
#include <netwm.h>
|
|
||||||
#include <QDialogButtonBox>
|
|
||||||
|
|
||||||
K_PLUGIN_FACTORY(KWinDesktopConfigFactory, registerPlugin<KWin::KWinDesktopConfig>();)
|
|
||||||
|
|
||||||
namespace KWin
|
|
||||||
{
|
|
||||||
|
|
||||||
KWinDesktopConfigForm::KWinDesktopConfigForm(QWidget* parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
KWinDesktopConfig::KWinDesktopConfig(QWidget* parent, const QVariantList& args)
|
|
||||||
: KCModule(KAboutData::pluginData(QStringLiteral("kcm_kwindesktop")), parent, args)
|
|
||||||
, m_config(KSharedConfig::openConfig("kwinrc"))
|
|
||||||
, m_actionCollection(nullptr)
|
|
||||||
, m_switchDesktopCollection(nullptr)
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::init()
|
|
||||||
{
|
|
||||||
m_ui = new KWinDesktopConfigForm(this);
|
|
||||||
// TODO: there has to be a way to add the shortcuts editor to the ui file
|
|
||||||
m_editor = new KShortcutsEditor(m_ui, KShortcutsEditor::GlobalAction);
|
|
||||||
m_ui->editorFrame->setLayout(new QVBoxLayout());
|
|
||||||
m_ui->editorFrame->layout()->setMargin(0);
|
|
||||||
m_ui->editorFrame->layout()->addWidget(m_editor);
|
|
||||||
|
|
||||||
m_ui->desktopNames->setDesktopConfig(this);
|
|
||||||
m_ui->desktopNames->setMaxDesktops(maxDesktops);
|
|
||||||
m_ui->desktopNames->numberChanged(defaultDesktops);
|
|
||||||
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
|
||||||
layout->addWidget(m_ui);
|
|
||||||
|
|
||||||
setQuickHelp(i18n("<h1>Multiple Desktops</h1>In this module, you can configure how many virtual desktops you want and how these should be labeled."));
|
|
||||||
|
|
||||||
// Shortcut config. The shortcut belongs to the component "kwin"!
|
|
||||||
m_actionCollection = new KActionCollection(this, QStringLiteral("kwin"));
|
|
||||||
m_actionCollection->setComponentDisplayName(i18n("KWin"));
|
|
||||||
m_actionCollection->setConfigGroup("Desktop Switching");
|
|
||||||
m_actionCollection->setConfigGlobal(true);
|
|
||||||
|
|
||||||
m_switchDesktopCollection = new KActionCollection(this, QStringLiteral("kwin"));
|
|
||||||
m_switchDesktopCollection->setComponentDisplayName(i18n("KWin"));
|
|
||||||
m_switchDesktopCollection->setConfigGroup("Desktop Switching");
|
|
||||||
m_switchDesktopCollection->setConfigGlobal(true);
|
|
||||||
|
|
||||||
// actions for switch desktop collection - other action is filled dynamically
|
|
||||||
addAction("Switch to Next Desktop", i18n("Switch to Next Desktop"));
|
|
||||||
addAction("Switch to Previous Desktop", i18n("Switch to Previous Desktop"));
|
|
||||||
addAction("Switch One Desktop to the Right", i18n("Switch One Desktop to the Right"));
|
|
||||||
addAction("Switch One Desktop to the Left", i18n("Switch One Desktop to the Left"));
|
|
||||||
addAction("Switch One Desktop Up", i18n("Switch One Desktop Up"));
|
|
||||||
addAction("Switch One Desktop Down", i18n("Switch One Desktop Down"));
|
|
||||||
addAction("Walk Through Desktops", i18n("Walk Through Desktops"));
|
|
||||||
addAction("Walk Through Desktops (Reverse)", i18n("Walk Through Desktops (Reverse)"));
|
|
||||||
addAction("Walk Through Desktop List", i18n("Walk Through Desktop List"));
|
|
||||||
addAction("Walk Through Desktop List (Reverse)", i18n("Walk Through Desktop List (Reverse)"));
|
|
||||||
|
|
||||||
m_editor->addCollection(m_switchDesktopCollection, i18n("Desktop Switching"));
|
|
||||||
|
|
||||||
// get number of desktops
|
|
||||||
int n = 1;
|
|
||||||
if (QX11Info::isPlatformX11()) {
|
|
||||||
NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames);
|
|
||||||
n = info.numberOfDesktops();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto addSwitchTo = [this](int i, const QKeySequence &sequence) {
|
|
||||||
QAction* a = m_actionCollection->addAction(QString("Switch to Desktop %1").arg(i));
|
|
||||||
a->setProperty("isConfigurationAction", true);
|
|
||||||
a->setText(i18n("Switch to Desktop %1", i));
|
|
||||||
KGlobalAccel::setGlobalShortcut(a, sequence);
|
|
||||||
};
|
|
||||||
if (n >= 2) {
|
|
||||||
addSwitchTo(1, Qt::CTRL + Qt::Key_F1);
|
|
||||||
addSwitchTo(2, Qt::CTRL + Qt::Key_F2);
|
|
||||||
}
|
|
||||||
if (n >= 3) {
|
|
||||||
addSwitchTo(3, Qt::CTRL + Qt::Key_F3);
|
|
||||||
}
|
|
||||||
if (n >= 4) {
|
|
||||||
addSwitchTo(4, Qt::CTRL + Qt::Key_F4);
|
|
||||||
}
|
|
||||||
for (int i = 5; i <= n; ++i) {
|
|
||||||
addSwitchTo(i, QKeySequence());
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should be after the "Switch to Desktop %1" loop. It HAS to be
|
|
||||||
// there after numberSpinBox is connected to slotChangeShortcuts. We would
|
|
||||||
// overwrite the users settings if not,
|
|
||||||
m_ui->numberSpinBox->setValue(n);
|
|
||||||
|
|
||||||
m_editor->addCollection(m_actionCollection, i18n("Desktop Switching"));
|
|
||||||
|
|
||||||
// search the effect names
|
|
||||||
// TODO: way to recognize if a effect is not found
|
|
||||||
KServiceTypeTrader* trader = KServiceTypeTrader::self();
|
|
||||||
QString fadedesktop;
|
|
||||||
KService::List services = trader->query("KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_fadedesktop'");
|
|
||||||
if (!services.isEmpty())
|
|
||||||
fadedesktop = services.first()->name();
|
|
||||||
|
|
||||||
m_ui->effectComboBox->addItem(i18n("No Animation"));
|
|
||||||
m_ui->effectComboBox->addItem(BuiltInEffects::effectData(BuiltInEffect::Slide).displayName);
|
|
||||||
m_ui->effectComboBox->addItem(BuiltInEffects::effectData(BuiltInEffect::CubeSlide).displayName);
|
|
||||||
m_ui->effectComboBox->addItem(fadedesktop);
|
|
||||||
|
|
||||||
// effect config and info button
|
|
||||||
m_ui->effectInfoButton->setIcon(QIcon::fromTheme("dialog-information"));
|
|
||||||
m_ui->effectConfigButton->setIcon(QIcon::fromTheme("configure"));
|
|
||||||
|
|
||||||
connect(m_ui->rowsSpinBox, SIGNAL(valueChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_ui->numberSpinBox, SIGNAL(valueChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_ui->numberSpinBox, SIGNAL(valueChanged(int)), SLOT(slotChangeShortcuts(int)));
|
|
||||||
connect(m_ui->desktopNames, SIGNAL(changed()), SLOT(changed()));
|
|
||||||
connect(m_ui->popupInfoCheckBox, SIGNAL(toggled(bool)), SLOT(changed()));
|
|
||||||
connect(m_ui->popupHideSpinBox, SIGNAL(valueChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_ui->desktopLayoutIndicatorCheckBox, SIGNAL(stateChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_ui->wrapAroundBox, SIGNAL(stateChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_editor, SIGNAL(keyChange()), SLOT(changed()));
|
|
||||||
connect(m_ui->allShortcutsCheckBox, SIGNAL(stateChanged(int)), SLOT(slotShowAllShortcuts()));
|
|
||||||
connect(m_ui->effectComboBox, SIGNAL(currentIndexChanged(int)), SLOT(changed()));
|
|
||||||
connect(m_ui->effectComboBox, SIGNAL(currentIndexChanged(int)), SLOT(slotEffectSelectionChanged(int)));
|
|
||||||
connect(m_ui->effectInfoButton, SIGNAL(clicked()), SLOT(slotAboutEffectClicked()));
|
|
||||||
connect(m_ui->effectConfigButton, SIGNAL(clicked()), SLOT(slotConfigureEffectClicked()));
|
|
||||||
|
|
||||||
// Begin check for immutable - taken from old desktops kcm
|
|
||||||
int kwin_screen_number = QX11Info::appScreen();
|
|
||||||
|
|
||||||
m_config = KSharedConfig::openConfig("kwinrc");
|
|
||||||
|
|
||||||
QByteArray groupname;
|
|
||||||
if (kwin_screen_number == 0)
|
|
||||||
groupname = "Desktops";
|
|
||||||
else
|
|
||||||
groupname = "Desktops-screen-" + QByteArray::number(kwin_screen_number);
|
|
||||||
|
|
||||||
if (m_config->isGroupImmutable(groupname)) {
|
|
||||||
m_ui->nameGroup->setEnabled(false);
|
|
||||||
//number of desktops widgets
|
|
||||||
m_ui->numberLabel->setEnabled(false);
|
|
||||||
m_ui->numberSpinBox->setEnabled(false);
|
|
||||||
m_ui->rowsSpinBox->setEnabled(false);
|
|
||||||
} else {
|
|
||||||
KConfigGroup cfgGroup(m_config.data(), groupname.constData());
|
|
||||||
if (cfgGroup.isEntryImmutable("Number")) {
|
|
||||||
//number of desktops widgets
|
|
||||||
m_ui->numberLabel->setEnabled(false);
|
|
||||||
m_ui->numberSpinBox->setEnabled(false);
|
|
||||||
m_ui->rowsSpinBox->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// End check for immutable
|
|
||||||
}
|
|
||||||
|
|
||||||
KWinDesktopConfig::~KWinDesktopConfig()
|
|
||||||
{
|
|
||||||
undo();
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::addAction(const QString &name, const QString &label)
|
|
||||||
{
|
|
||||||
QAction* a = m_switchDesktopCollection->addAction(name);
|
|
||||||
a->setProperty("isConfigurationAction", true);
|
|
||||||
a->setText(label);
|
|
||||||
KGlobalAccel::setGlobalShortcut(a, QKeySequence());
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::defaults()
|
|
||||||
{
|
|
||||||
// TODO: plasma stuff
|
|
||||||
m_ui->numberSpinBox->setValue(defaultDesktops);
|
|
||||||
m_ui->desktopNames->numberChanged(defaultDesktops);
|
|
||||||
for (int i = 1; i <= maxDesktops; i++) {
|
|
||||||
m_desktopNames[i-1] = i18n("Desktop %1", i);
|
|
||||||
if (i <= defaultDesktops)
|
|
||||||
m_ui->desktopNames->setDefaultName(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// popup info
|
|
||||||
m_ui->popupInfoCheckBox->setChecked(false);
|
|
||||||
m_ui->popupHideSpinBox->setValue(1000);
|
|
||||||
m_ui->desktopLayoutIndicatorCheckBox->setChecked(true);
|
|
||||||
|
|
||||||
m_ui->effectComboBox->setCurrentIndex(1);
|
|
||||||
|
|
||||||
m_ui->wrapAroundBox->setChecked(true);
|
|
||||||
|
|
||||||
m_ui->rowsSpinBox->setValue(2);
|
|
||||||
|
|
||||||
m_editor->allDefault();
|
|
||||||
|
|
||||||
emit changed(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void KWinDesktopConfig::load()
|
|
||||||
{
|
|
||||||
// This method is called on reset(). So undo all changes.
|
|
||||||
undo();
|
|
||||||
|
|
||||||
if (QX11Info::isPlatformX11()) {
|
|
||||||
// get number of desktops
|
|
||||||
NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout);
|
|
||||||
|
|
||||||
for (int i = 1; i <= maxDesktops; i++) {
|
|
||||||
QString name = QString::fromUtf8(info.desktopName(i));
|
|
||||||
m_desktopNames << name;
|
|
||||||
m_ui->desktopNames->setName(i, name);
|
|
||||||
}
|
|
||||||
m_ui->rowsSpinBox->setValue(info.desktopLayoutColumnsRows().height());
|
|
||||||
} else {
|
|
||||||
// TODO: proper implementation
|
|
||||||
m_ui->rowsSpinBox->setValue(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Popup info
|
|
||||||
KConfigGroup effectconfig(m_config, "Plugins");
|
|
||||||
KConfigGroup popupInfo(m_config, "Script-desktopchangeosd");
|
|
||||||
m_ui->popupInfoCheckBox->setChecked(effectconfig.readEntry("desktopchangeosdEnabled", false));
|
|
||||||
m_ui->popupHideSpinBox->setValue(popupInfo.readEntry("PopupHideDelay", 1000));
|
|
||||||
m_ui->desktopLayoutIndicatorCheckBox->setChecked(!popupInfo.readEntry("TextOnly", false));
|
|
||||||
|
|
||||||
// Wrap Around on screen edge
|
|
||||||
KConfigGroup windowConfig(m_config, "Windows");
|
|
||||||
m_ui->wrapAroundBox->setChecked(windowConfig.readEntry<bool>("RollOverDesktops", true));
|
|
||||||
|
|
||||||
// Effect for desktop switching
|
|
||||||
// Set current option to "none" if no plugin is activated.
|
|
||||||
m_ui->effectComboBox->setCurrentIndex(0);
|
|
||||||
auto enableBuiltInEffect = [&effectconfig,this](BuiltInEffect effect, int index) {
|
|
||||||
const QString key = BuiltInEffects::nameForEffect(effect) + QStringLiteral("Enabled");
|
|
||||||
if (effectconfig.readEntry(key, BuiltInEffects::enabledByDefault(effect))) {
|
|
||||||
m_ui->effectComboBox->setCurrentIndex(index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
enableBuiltInEffect(BuiltInEffect::Slide, 1);
|
|
||||||
enableBuiltInEffect(BuiltInEffect::CubeSlide, 2);
|
|
||||||
if (effectEnabled("fadedesktop", effectconfig))
|
|
||||||
m_ui->effectComboBox->setCurrentIndex(3);
|
|
||||||
slotEffectSelectionChanged(m_ui->effectComboBox->currentIndex());
|
|
||||||
// TODO: plasma stuff
|
|
||||||
|
|
||||||
emit changed(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::save()
|
|
||||||
{
|
|
||||||
// TODO: plasma stuff
|
|
||||||
|
|
||||||
const int numberDesktops = m_ui->numberSpinBox->value();
|
|
||||||
int rows = m_ui->rowsSpinBox->value();
|
|
||||||
rows = qBound(1, rows, numberDesktops);
|
|
||||||
// avoid weird cases like having 3 rows for 4 desktops, where the last row is unused
|
|
||||||
int columns = numberDesktops / rows;
|
|
||||||
if (numberDesktops % rows > 0) {
|
|
||||||
columns++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (QX11Info::isPlatformX11()) {
|
|
||||||
NETRootInfo info(QX11Info::connection(), NET::NumberOfDesktops | NET::DesktopNames, NET::WM2DesktopLayout);
|
|
||||||
// set desktop names
|
|
||||||
for (int i = 1; i <= maxDesktops; i++) {
|
|
||||||
QString desktopName = m_desktopNames[ i -1 ];
|
|
||||||
if (i <= m_ui->numberSpinBox->value())
|
|
||||||
desktopName = m_ui->desktopNames->name(i);
|
|
||||||
info.setDesktopName(i, desktopName.toUtf8());
|
|
||||||
info.activate();
|
|
||||||
}
|
|
||||||
// set number of desktops
|
|
||||||
info.setNumberOfDesktops(numberDesktops);
|
|
||||||
info.activate();
|
|
||||||
info.setDesktopLayout(NET::OrientationHorizontal, columns, rows, NET::DesktopLayoutCornerTopLeft);
|
|
||||||
info.activate();
|
|
||||||
|
|
||||||
XSync(QX11Info::display(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the desktops
|
|
||||||
QString groupname;
|
|
||||||
const int screenNumber = QX11Info::appScreen();
|
|
||||||
if (screenNumber == 0)
|
|
||||||
groupname = "Desktops";
|
|
||||||
else
|
|
||||||
groupname.sprintf("Desktops-screen-%d", screenNumber);
|
|
||||||
KConfigGroup group(m_config, groupname);
|
|
||||||
group.writeEntry("Rows", rows);
|
|
||||||
|
|
||||||
// Popup info
|
|
||||||
KConfigGroup effectconfig(m_config, "Plugins");
|
|
||||||
KConfigGroup popupInfo(m_config, "Script-desktopchangeosd");
|
|
||||||
effectconfig.writeEntry("desktopchangeosdEnabled", m_ui->popupInfoCheckBox->isChecked());
|
|
||||||
popupInfo.writeEntry("PopupHideDelay", m_ui->popupHideSpinBox->value());
|
|
||||||
popupInfo.writeEntry("TextOnly", !m_ui->desktopLayoutIndicatorCheckBox->isChecked());
|
|
||||||
|
|
||||||
// Wrap Around on screen edge
|
|
||||||
KConfigGroup windowConfig(m_config, "Windows");
|
|
||||||
windowConfig.writeEntry("RollOverDesktops", m_ui->wrapAroundBox->isChecked());
|
|
||||||
|
|
||||||
// Effect desktop switching
|
|
||||||
int desktopSwitcher = m_ui->effectComboBox->currentIndex();
|
|
||||||
bool slideEnabled = false;
|
|
||||||
bool cubeSlideEnabled = false;
|
|
||||||
bool fadeEnabled = false;
|
|
||||||
switch(desktopSwitcher) {
|
|
||||||
case 1:
|
|
||||||
// slide
|
|
||||||
slideEnabled = true;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
// cube
|
|
||||||
cubeSlideEnabled = true;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// fadedesktop
|
|
||||||
fadeEnabled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
effectconfig.writeEntry("slideEnabled", slideEnabled);
|
|
||||||
effectconfig.writeEntry("cubeslideEnabled", cubeSlideEnabled);
|
|
||||||
effectconfig.writeEntry("kwin4_effect_fadedesktopEnabled", fadeEnabled);
|
|
||||||
|
|
||||||
m_editor->save();
|
|
||||||
|
|
||||||
m_config->sync();
|
|
||||||
// Send signal to all kwin instances
|
|
||||||
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
|
|
||||||
QDBusConnection::sessionBus().send(message);
|
|
||||||
// and reconfigure the effects
|
|
||||||
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"),
|
|
||||||
QStringLiteral("/Effects"),
|
|
||||||
QDBusConnection::sessionBus());
|
|
||||||
if (slideEnabled) {
|
|
||||||
interface.loadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Slide));
|
|
||||||
} else {
|
|
||||||
interface.unloadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::Slide));
|
|
||||||
}
|
|
||||||
if (cubeSlideEnabled) {
|
|
||||||
interface.loadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide));
|
|
||||||
} else {
|
|
||||||
interface.unloadEffect(BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide));
|
|
||||||
}
|
|
||||||
if (fadeEnabled) {
|
|
||||||
interface.loadEffect(QStringLiteral("kwin4_effect_fadedesktop"));
|
|
||||||
} else {
|
|
||||||
interface.unloadEffect(QStringLiteral("kwin4_effect_fadedesktop"));
|
|
||||||
}
|
|
||||||
|
|
||||||
emit changed(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void KWinDesktopConfig::undo()
|
|
||||||
{
|
|
||||||
// The global shortcuts editor makes changes active immediately. In case
|
|
||||||
// of undo we have to undo them manually
|
|
||||||
m_editor->undoChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString KWinDesktopConfig::cachedDesktopName(int desktop)
|
|
||||||
{
|
|
||||||
if (desktop > m_desktopNames.size())
|
|
||||||
return QString();
|
|
||||||
return m_desktopNames[ desktop -1 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
QString KWinDesktopConfig::extrapolatedShortcut(int desktop) const
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!desktop || desktop > m_actionCollection->count())
|
|
||||||
return QString();
|
|
||||||
if (desktop == 1)
|
|
||||||
return QString("Ctrl+F1");
|
|
||||||
|
|
||||||
QAction *beforeAction = m_actionCollection->actions().at(qMin(9, desktop - 2));
|
|
||||||
auto shortcuts = KGlobalAccel::self()->shortcut(beforeAction);
|
|
||||||
if (shortcuts.isEmpty()) {
|
|
||||||
shortcuts = KGlobalAccel::self()->defaultShortcut(beforeAction);
|
|
||||||
}
|
|
||||||
QString before;
|
|
||||||
if (!shortcuts.isEmpty()) {
|
|
||||||
before = shortcuts.first().toString(QKeySequence::PortableText);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString seq;
|
|
||||||
if (before.contains(QRegExp("F[0-9]{1,2}"))) {
|
|
||||||
if (desktop < 13) // 10?
|
|
||||||
seq = QString("F%1").arg(desktop);
|
|
||||||
else if (!before.contains("Shift"))
|
|
||||||
seq = "Shift+" + QString("F%1").arg(desktop - 10);
|
|
||||||
} else if (before.contains(QRegExp("[0-9]"))) {
|
|
||||||
if (desktop == 10)
|
|
||||||
seq = '0';
|
|
||||||
else if (desktop > 10) {
|
|
||||||
if (!before.contains("Shift"))
|
|
||||||
seq = "Shift+" + QString::number(desktop == 20 ? 0 : (desktop - 10));
|
|
||||||
} else
|
|
||||||
seq = QString::number(desktop);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!seq.isEmpty()) {
|
|
||||||
if (before.contains("Ctrl"))
|
|
||||||
seq.prepend("Ctrl+");
|
|
||||||
if (before.contains("Alt"))
|
|
||||||
seq.prepend("Alt+");
|
|
||||||
if (before.contains("Shift"))
|
|
||||||
seq.prepend("Shift+");
|
|
||||||
if (before.contains("Meta"))
|
|
||||||
seq.prepend("Meta+");
|
|
||||||
}
|
|
||||||
return seq;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::slotChangeShortcuts(int number)
|
|
||||||
{
|
|
||||||
if ((number < 1) || (number > maxDesktops))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_ui->allShortcutsCheckBox->isChecked())
|
|
||||||
number = maxDesktops;
|
|
||||||
|
|
||||||
while (number != m_actionCollection->count()) {
|
|
||||||
if (number < m_actionCollection->count()) {
|
|
||||||
// Remove the action from the action collection. The action itself
|
|
||||||
// will still exist because that's the way kwin currently works.
|
|
||||||
// No need to remove/forget it. See kwinbindings.
|
|
||||||
QAction *a = m_actionCollection->takeAction(m_actionCollection->actions().last());
|
|
||||||
// Remove any associated global shortcut. Set it to ""
|
|
||||||
KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>(), KGlobalAccel::NoAutoloading);
|
|
||||||
m_ui->messageLabel->hide();
|
|
||||||
delete a;
|
|
||||||
} else {
|
|
||||||
// add desktop
|
|
||||||
int desktop = m_actionCollection->count() + 1;
|
|
||||||
QAction* action = m_actionCollection->addAction(QString("Switch to Desktop %1").arg(desktop));
|
|
||||||
action->setProperty("isConfigurationAction", true);
|
|
||||||
action->setText(i18n("Switch to Desktop %1", desktop));
|
|
||||||
KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>());
|
|
||||||
QString shortcutString = extrapolatedShortcut(desktop);
|
|
||||||
if (shortcutString.isEmpty()) {
|
|
||||||
m_ui->messageLabel->setText(i18n("No suitable Shortcut for Desktop %1 found", desktop));
|
|
||||||
m_ui->messageLabel->show();
|
|
||||||
} else {
|
|
||||||
QKeySequence shortcut(shortcutString);
|
|
||||||
if (!shortcut.isEmpty() && KGlobalAccel::self()->isGlobalShortcutAvailable(shortcut)) {
|
|
||||||
KGlobalAccel::self()->setShortcut(action, QList<QKeySequence>() << shortcut, KGlobalAccel::NoAutoloading);
|
|
||||||
m_ui->messageLabel->setText(i18n("Assigned global Shortcut \"%1\" to Desktop %2", shortcutString, desktop));
|
|
||||||
m_ui->messageLabel->show();
|
|
||||||
} else {
|
|
||||||
m_ui->messageLabel->setText(i18n("Shortcut conflict: Could not set Shortcut %1 for Desktop %2", shortcutString, desktop));
|
|
||||||
m_ui->messageLabel->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_editor->clearCollections();
|
|
||||||
m_editor->addCollection(m_switchDesktopCollection, i18n("Desktop Switching"));
|
|
||||||
m_editor->addCollection(m_actionCollection, i18n("Desktop Switching"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::slotShowAllShortcuts()
|
|
||||||
{
|
|
||||||
slotChangeShortcuts(m_ui->numberSpinBox->value());
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::slotEffectSelectionChanged(int index)
|
|
||||||
{
|
|
||||||
bool enabled = false;
|
|
||||||
if (index != 0)
|
|
||||||
enabled = true;
|
|
||||||
m_ui->effectInfoButton->setEnabled(enabled);
|
|
||||||
|
|
||||||
switch (index) {
|
|
||||||
case 1: // Slide
|
|
||||||
case 2: // Cube Slide
|
|
||||||
enabled = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
enabled = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
m_ui->effectConfigButton->setEnabled(enabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool KWinDesktopConfig::effectEnabled(const QString& effect, const KConfigGroup& cfg) const
|
|
||||||
{
|
|
||||||
KService::List services = KServiceTypeTrader::self()->query(
|
|
||||||
"KWin/Effect", "[X-KDE-PluginInfo-Name] == 'kwin4_effect_" + effect + '\'');
|
|
||||||
if (services.isEmpty())
|
|
||||||
return false;
|
|
||||||
QVariant v = services.first()->property("X-KDE-PluginInfo-EnabledByDefault");
|
|
||||||
return cfg.readEntry("kwin4_effect_" + effect + "Enabled", v.toBool());
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::slotAboutEffectClicked()
|
|
||||||
{
|
|
||||||
QString effect;
|
|
||||||
bool fromKService = false;
|
|
||||||
BuiltInEffect builtIn = BuiltInEffect::Invalid;
|
|
||||||
switch(m_ui->effectComboBox->currentIndex()) {
|
|
||||||
case 1:
|
|
||||||
builtIn = BuiltInEffect::Slide;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
builtIn = BuiltInEffect::CubeSlide;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
effect = "fadedesktop";
|
|
||||||
fromKService = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto showDialog = [this](const KAboutData &aboutData) {
|
|
||||||
QPointer<KAboutApplicationDialog> aboutPlugin = new KAboutApplicationDialog(aboutData, this);
|
|
||||||
aboutPlugin->exec();
|
|
||||||
delete aboutPlugin;
|
|
||||||
};
|
|
||||||
if (fromKService) {
|
|
||||||
const QString pluginId = QStringLiteral("kwin4_effect_%1").arg(effect);
|
|
||||||
const auto effectsMetaData = KPackage::PackageLoader::self()->findPackages(
|
|
||||||
QStringLiteral("KWin/Effect"),
|
|
||||||
QStringLiteral("kwin/effects/"),
|
|
||||||
[&pluginId](const KPluginMetaData &meta) {
|
|
||||||
return meta.pluginId() == pluginId;
|
|
||||||
});
|
|
||||||
if (effectsMetaData.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
KPluginInfo pluginInfo(effectsMetaData.first());
|
|
||||||
|
|
||||||
const QString name = pluginInfo.name();
|
|
||||||
const QString comment = pluginInfo.comment();
|
|
||||||
const QString author = pluginInfo.author();
|
|
||||||
const QString email = pluginInfo.email();
|
|
||||||
const QString website = pluginInfo.website();
|
|
||||||
const QString version = pluginInfo.version();
|
|
||||||
const QString license = pluginInfo.license();
|
|
||||||
const QString icon = pluginInfo.icon();
|
|
||||||
|
|
||||||
KAboutData aboutData(name, name, version, comment, KAboutLicense::byKeyword(license).key(), QString(), QString(), website.toLatin1());
|
|
||||||
aboutData.setProgramLogo(icon);
|
|
||||||
const QStringList authors = author.split(',');
|
|
||||||
const QStringList emails = email.split(',');
|
|
||||||
int i = 0;
|
|
||||||
if (authors.count() == emails.count()) {
|
|
||||||
foreach (const QString & author, authors) {
|
|
||||||
if (!author.isEmpty()) {
|
|
||||||
aboutData.addAuthor(i18n(author.toUtf8()), QString(), emails[i]);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showDialog(aboutData);
|
|
||||||
} else {
|
|
||||||
const BuiltInEffects::EffectData &data = BuiltInEffects::effectData(builtIn);
|
|
||||||
KAboutData aboutData(data.name,
|
|
||||||
data.displayName,
|
|
||||||
QStringLiteral(KWIN_VERSION_STRING),
|
|
||||||
data.comment,
|
|
||||||
KAboutLicense::GPL_V2);
|
|
||||||
aboutData.setProgramLogo(QIcon::fromTheme(QStringLiteral("preferences-system-windows")));
|
|
||||||
aboutData.addAuthor(i18n("KWin development team"));
|
|
||||||
showDialog(aboutData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KWinDesktopConfig::slotConfigureEffectClicked()
|
|
||||||
{
|
|
||||||
QString effect;
|
|
||||||
switch(m_ui->effectComboBox->currentIndex()) {
|
|
||||||
case 1:
|
|
||||||
effect = BuiltInEffects::nameForEffect(BuiltInEffect::Slide);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
effect = BuiltInEffects::nameForEffect(BuiltInEffect::CubeSlide);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPointer<QDialog> configDialog = new QDialog(this);
|
|
||||||
KCModule *kcm = KPluginTrader::createInstanceFromQuery<KCModule>(QStringLiteral("kwin/effects/configs/"), QString(),
|
|
||||||
QStringLiteral("'%1' in [X-KDE-ParentComponents]").arg(effect),
|
|
||||||
configDialog);
|
|
||||||
if (!kcm) {
|
|
||||||
delete configDialog;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
configDialog->setWindowTitle(m_ui->effectComboBox->currentText());
|
|
||||||
configDialog->setLayout(new QVBoxLayout);
|
|
||||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel|QDialogButtonBox::RestoreDefaults, configDialog);
|
|
||||||
connect(buttons, SIGNAL(accepted()), configDialog, SLOT(accept()));
|
|
||||||
connect(buttons, SIGNAL(rejected()), configDialog, SLOT(reject()));
|
|
||||||
connect(buttons->button(QDialogButtonBox::RestoreDefaults), SIGNAL(clicked(bool)), kcm, SLOT(defaults()));
|
|
||||||
|
|
||||||
QWidget *showWidget = new QWidget(configDialog);
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
|
||||||
showWidget->setLayout(layout);
|
|
||||||
layout->addWidget(kcm);
|
|
||||||
configDialog->layout()->addWidget(showWidget);
|
|
||||||
configDialog->layout()->addWidget(buttons);
|
|
||||||
|
|
||||||
if (configDialog->exec() == QDialog::Accepted) {
|
|
||||||
kcm->save();
|
|
||||||
} else {
|
|
||||||
kcm->load();
|
|
||||||
}
|
|
||||||
delete configDialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#include "main.moc"
|
|
|
@ -1,92 +0,0 @@
|
||||||
/********************************************************************
|
|
||||||
KWin - the KDE window manager
|
|
||||||
This file is part of the KDE project.
|
|
||||||
|
|
||||||
Copyright (C) 2009 Martin Gräßlin <mgraesslin@kde.org>
|
|
||||||
|
|
||||||
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 2 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/>.
|
|
||||||
*********************************************************************/
|
|
||||||
#ifndef __MAIN_H__
|
|
||||||
#define __MAIN_H__
|
|
||||||
|
|
||||||
#include <kcmodule.h>
|
|
||||||
#include <ksharedconfig.h>
|
|
||||||
|
|
||||||
#include "ui_main.h"
|
|
||||||
|
|
||||||
class KActionCollection;
|
|
||||||
class KConfigGroup;
|
|
||||||
class KShortcutsEditor;
|
|
||||||
|
|
||||||
namespace KWin
|
|
||||||
{
|
|
||||||
// if you change this, update also the number of keyboard shortcuts in kwin/kwinbindings.cpp
|
|
||||||
static const int maxDesktops = 20;
|
|
||||||
static const int defaultDesktops = 4;
|
|
||||||
|
|
||||||
class KWinDesktopConfigForm : public QWidget, public Ui::KWinDesktopConfigForm
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KWinDesktopConfigForm(QWidget* parent);
|
|
||||||
};
|
|
||||||
|
|
||||||
class KWinDesktopConfig : public KCModule
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit KWinDesktopConfig(QWidget* parent, const QVariantList& args);
|
|
||||||
~KWinDesktopConfig();
|
|
||||||
QString cachedDesktopName(int desktop);
|
|
||||||
|
|
||||||
// undo all changes
|
|
||||||
void undo();
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
|
||||||
virtual void save();
|
|
||||||
virtual void load();
|
|
||||||
virtual void defaults();
|
|
||||||
|
|
||||||
|
|
||||||
private Q_SLOTS:
|
|
||||||
void slotChangeShortcuts(int number);
|
|
||||||
void slotShowAllShortcuts();
|
|
||||||
void slotEffectSelectionChanged(int index);
|
|
||||||
void slotAboutEffectClicked();
|
|
||||||
void slotConfigureEffectClicked();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void init();
|
|
||||||
void addAction(const QString &name, const QString &label);
|
|
||||||
bool effectEnabled(const QString& effect, const KConfigGroup& cfg) const;
|
|
||||||
QString extrapolatedShortcut(int desktop) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
KWinDesktopConfigForm* m_ui;
|
|
||||||
KSharedConfigPtr m_config;
|
|
||||||
// cache for desktop names given by NETRootInfo
|
|
||||||
// needed as the widget only stores the names for actual number of desktops
|
|
||||||
QStringList m_desktopNames;
|
|
||||||
// Collection for switching desktops like ctrl+f1
|
|
||||||
KActionCollection* m_actionCollection;
|
|
||||||
// Collection for next, previous, up, down desktop
|
|
||||||
KActionCollection* m_switchDesktopCollection;
|
|
||||||
KShortcutsEditor* m_editor;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,326 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>KWinDesktopConfigForm</class>
|
|
||||||
<widget class="QWidget" name="KWinDesktopConfigForm">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>572</width>
|
|
||||||
<height>310</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
|
||||||
<property name="currentIndex">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="desktop">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Desktops</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
|
||||||
<property name="title">
|
|
||||||
<string>Layout</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QFormLayout" name="formLayout_2">
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<property name="verticalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="numberLabel">
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string>Here you can set how many virtual desktops you want on your KDE desktop.</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>&Number of desktops:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>numberSpinBox</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QSpinBox" name="numberSpinBox">
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string>Here you can set how many virtual desktops you want on your KDE desktop.</string>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>20</number>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>N&umber of rows:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>rowsSpinBox</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QSpinBox" name="rowsSpinBox">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>20</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="nameGroup">
|
|
||||||
<property name="title">
|
|
||||||
<string>Desktop Names</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="KWin::DesktopNamesWidget" name="desktopNames" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="messageLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="switching">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Switching</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="wrapAroundBox">
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string>Enable this option if you want keyboard or active desktop border navigation beyond the edge of a desktop to take you to the opposite edge of the new desktop.</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Desktop navigation wraps around</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Desktop Effect Animation</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QFormLayout" name="formLayout_3">
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<property name="verticalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Animation:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>effectComboBox</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="effectComboBox">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="effectConfigButton">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="effectInfoButton"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="popupInfoCheckBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Desktop Switch On-Screen Display</string>
|
|
||||||
</property>
|
|
||||||
<property name="checkable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QFormLayout" name="formLayout">
|
|
||||||
<property name="fieldGrowthPolicy">
|
|
||||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
|
||||||
</property>
|
|
||||||
<property name="verticalSpacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="hideLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Duration:</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>popupHideSpinBox</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QSpinBox" name="popupHideSpinBox">
|
|
||||||
<property name="suffix">
|
|
||||||
<string> msec</string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>5000</number>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<number>50</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" colspan="2">
|
|
||||||
<widget class="QCheckBox" name="desktopLayoutIndicatorCheckBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Enabling this option will show a small preview of the desktop layout indicating the selected desktop.</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Show desktop layout indicators</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="shortcutsGroupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Shortcuts</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QFrame" name="editorFrame">
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::NoFrame</enum>
|
|
||||||
</property>
|
|
||||||
<property name="frameShadow">
|
|
||||||
<enum>QFrame::Plain</enum>
|
|
||||||
</property>
|
|
||||||
<property name="lineWidth">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="allShortcutsCheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Show shortcuts for all possible desktops</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>KWin::DesktopNamesWidget</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>desktopnameswidget.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
<slots>
|
|
||||||
<slot>numberChanged(int)</slot>
|
|
||||||
</slots>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>numberSpinBox</sender>
|
|
||||||
<signal>valueChanged(int)</signal>
|
|
||||||
<receiver>desktopNames</receiver>
|
|
||||||
<slot>numberChanged(int)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>327</x>
|
|
||||||
<y>144</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>326</x>
|
|
||||||
<y>209</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
253
kcmkwin/kwindesktop/package/contents/ui/main.qml
Normal file
253
kcmkwin/kwindesktop/package/contents/ui/main.qml
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Eike Hein <hein@kde.org>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.1
|
||||||
|
import QtQuick.Layouts 1.1
|
||||||
|
import QtQuick.Controls 2.4 as QtControls
|
||||||
|
import org.kde.kirigami 2.5 as Kirigami
|
||||||
|
import org.kde.plasma.core 2.1 as PlasmaCore
|
||||||
|
import org.kde.kcm 1.2
|
||||||
|
|
||||||
|
ScrollViewKCM {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
ConfigModule.quickHelp: i18n("Virtual Desktops")
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: kcm.desktopsModel
|
||||||
|
|
||||||
|
onReadyChanged: {
|
||||||
|
rowsSpinBox.value = kcm.desktopsModel.rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
onRowsChanged: {
|
||||||
|
rowsSpinBox.value = kcm.desktopsModel.rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: desktopsListItemComponent
|
||||||
|
|
||||||
|
Kirigami.SwipeListItem {
|
||||||
|
id: listItem
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
QtControls.TextField {
|
||||||
|
id: nameField
|
||||||
|
|
||||||
|
background: null
|
||||||
|
leftPadding: Kirigami.Units.largeSpacing
|
||||||
|
topPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
text: model.display
|
||||||
|
|
||||||
|
readOnly: true
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
readOnly = true;
|
||||||
|
Qt.callLater(kcm.desktopsModel.setDesktopName, model.Id, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actions: [
|
||||||
|
Kirigami.Action {
|
||||||
|
enabled: !model.IsMissing
|
||||||
|
iconName: "edit-rename"
|
||||||
|
tooltip: i18nc("@info:tooltip", "Rename")
|
||||||
|
onTriggered: {
|
||||||
|
nameField.readOnly = false;
|
||||||
|
nameField.selectAll();
|
||||||
|
nameField.forceActiveFocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Kirigami.Action {
|
||||||
|
enabled: !model.IsMissing
|
||||||
|
iconName: "list-remove"
|
||||||
|
tooltip: i18nc("@info:tooltip", "Remove")
|
||||||
|
onTriggered: kcm.desktopsModel.removeDesktop(model.Id)
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header: ColumnLayout {
|
||||||
|
id: messagesLayout
|
||||||
|
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
Kirigami.InlineMessage {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
type: Kirigami.MessageType.Error
|
||||||
|
|
||||||
|
text: kcm.desktopsModel.error
|
||||||
|
|
||||||
|
visible: kcm.desktopsModel.error != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Kirigami.InlineMessage {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
type: Kirigami.MessageType.Information
|
||||||
|
|
||||||
|
text: i18n("Virtual desktops have been changed outside this settings application. Saving now will overwrite the changes.")
|
||||||
|
|
||||||
|
visible: kcm.desktopsModel.serverModified
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
QtControls.Label {
|
||||||
|
text: i18n("Rows:")
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControls.SpinBox {
|
||||||
|
id: rowsSpinBox
|
||||||
|
|
||||||
|
from: 1
|
||||||
|
to: 20
|
||||||
|
|
||||||
|
onValueModified: kcm.desktopsModel.rows = value
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { // Spacer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControls.Button {
|
||||||
|
Layout.alignment: Qt.AlignRight
|
||||||
|
|
||||||
|
text: i18nc("@action:button", "Add")
|
||||||
|
icon.name: "list-add"
|
||||||
|
|
||||||
|
onClicked: kcm.desktopsModel.createDesktop(i18n("New Desktop"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view: ListView {
|
||||||
|
id: desktopsList
|
||||||
|
|
||||||
|
model: kcm.desktopsModel.ready ? kcm.desktopsModel : null
|
||||||
|
|
||||||
|
section.property: "DesktopRow"
|
||||||
|
section.delegate: Kirigami.AbstractListItem {
|
||||||
|
width: desktopsList.width
|
||||||
|
|
||||||
|
backgroundColor: Kirigami.Theme.backgroundColor
|
||||||
|
|
||||||
|
hoverEnabled: false
|
||||||
|
supportsMouseEvents: false
|
||||||
|
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
|
|
||||||
|
QtControls.Label {
|
||||||
|
text: i18n("Row %1", section)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Kirigami.DelegateRecycler {
|
||||||
|
width: desktopsList.width
|
||||||
|
|
||||||
|
sourceComponent: desktopsListItemComponent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: ColumnLayout {
|
||||||
|
Kirigami.FormLayout {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: kcm
|
||||||
|
|
||||||
|
onNavWrapsChanged: navWraps.checked = kcm.navWraps
|
||||||
|
|
||||||
|
onOsdEnabledChanged: osdEnabled.checked = kcm.osdEnabled
|
||||||
|
onOsdDurationChanged: osdDuration.value = kcm.osdDuration
|
||||||
|
onOsdTextOnlyChanged: osdTextOnly.checked = !kcm.osdTextOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControls.CheckBox {
|
||||||
|
id: navWraps
|
||||||
|
|
||||||
|
Kirigami.FormData.label: i18n("Options:")
|
||||||
|
|
||||||
|
text: i18n("Navigation wraps around")
|
||||||
|
|
||||||
|
checked: kcm.navWraps
|
||||||
|
|
||||||
|
onCheckedChanged: kcm.navWraps = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
QtControls.CheckBox {
|
||||||
|
id: osdEnabled
|
||||||
|
|
||||||
|
text: i18n("Show on-screen display when switching:")
|
||||||
|
|
||||||
|
checked: kcm.osdEnabled
|
||||||
|
|
||||||
|
onCheckedChanged: kcm.osdEnabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControls.SpinBox {
|
||||||
|
id: osdDuration
|
||||||
|
|
||||||
|
from: 0
|
||||||
|
to: 10000
|
||||||
|
stepSize: 100
|
||||||
|
|
||||||
|
textFromValue: function(value, locale) { return i18n("%1 ms", value)}
|
||||||
|
|
||||||
|
value: kcm.osdDuration
|
||||||
|
|
||||||
|
onValueChanged: kcm.osdDuration = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: units.largeSpacing
|
||||||
|
}
|
||||||
|
|
||||||
|
QtControls.CheckBox {
|
||||||
|
id: osdTextOnly
|
||||||
|
|
||||||
|
enabled: osdEnabled.checked
|
||||||
|
|
||||||
|
text: i18n("Show desktop layout indicators")
|
||||||
|
|
||||||
|
checked: kcm.osdTextOnly
|
||||||
|
|
||||||
|
onCheckedChanged: kcm.osdTextOnly = !checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
116
kcmkwin/kwindesktop/package/metadata.desktop
Normal file
116
kcmkwin/kwindesktop/package/metadata.desktop
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Virtual Desktops
|
||||||
|
Name[ar]=أسطح المكتب الافتراضية
|
||||||
|
Name[bg]=Виртуални работни плотове
|
||||||
|
Name[bs]=Virtuelne površi
|
||||||
|
Name[ca]=Escriptoris virtuals
|
||||||
|
Name[ca@valencia]=Escriptoris virtuals
|
||||||
|
Name[cs]=Virtuální plochy
|
||||||
|
Name[da]=Virtuelle skriveborde
|
||||||
|
Name[de]=Virtuelle Arbeitsflächen
|
||||||
|
Name[el]=Εικονικές επιφάνειες εργασίες
|
||||||
|
Name[en_GB]=Virtual Desktops
|
||||||
|
Name[es]=Escritorios virtuales
|
||||||
|
Name[et]=Virtuaalsed töölauad
|
||||||
|
Name[eu]=Alegiazko mahaigaina
|
||||||
|
Name[fi]=Virtuaalityöpöydät
|
||||||
|
Name[fr]=Bureaux virtuels
|
||||||
|
Name[ga]=Deasca Fíorúla
|
||||||
|
Name[gl]=Escritorios virtuais
|
||||||
|
Name[gu]=વર્ચ્યુઅલ ડેસ્કટોપો
|
||||||
|
Name[he]=שולחנות עבודה וירטואליים
|
||||||
|
Name[hi]=आभासी डेस्कटॉप
|
||||||
|
Name[hr]=Virtualne radne površine
|
||||||
|
Name[hu]=Virtuális asztalok
|
||||||
|
Name[ia]=Scriptorios virtual
|
||||||
|
Name[id]=Desktop Virtual
|
||||||
|
Name[is]=Sýndarskjáborð
|
||||||
|
Name[it]=Desktop virtuali
|
||||||
|
Name[ja]=仮想デスクトップ
|
||||||
|
Name[kk]=Виртуалды Үстелдер
|
||||||
|
Name[km]=ផ្ទៃតុនិម្មិត
|
||||||
|
Name[kn]=ವಾಸ್ತವಪ್ರಾಯ ಗಣಕತೆರೆಗಳು
|
||||||
|
Name[ko]=가상 데스크톱
|
||||||
|
Name[lt]=Virtualūs darbalaukiai
|
||||||
|
Name[lv]=Virtuālās darbvirsmas
|
||||||
|
Name[mr]=आभासी डेस्कटॉप
|
||||||
|
Name[nb]=Virtuelle skrivebord
|
||||||
|
Name[nds]=Mehr Schriefdischen
|
||||||
|
Name[nl]=Virtuele bureaubladen
|
||||||
|
Name[nn]=Virtuelle skrivebord
|
||||||
|
Name[pa]=ਵਰਚੁਅਲ ਡੈਸਕਟਾਪ
|
||||||
|
Name[pl]=Pulpity wirtualne
|
||||||
|
Name[pt]=Ecrãs Virtuais
|
||||||
|
Name[pt_BR]=Áreas de trabalho virtuais
|
||||||
|
Name[ro]=Birouri virtuale
|
||||||
|
Name[ru]=Рабочие столы
|
||||||
|
Name[si]=අත්ථ්ය වැඩතල
|
||||||
|
Name[sk]=Virtuálne pracovné plochy
|
||||||
|
Name[sl]=Navidezna namizja
|
||||||
|
Name[sr]=Виртуелне површи
|
||||||
|
Name[sr@ijekavian]=Виртуелне површи
|
||||||
|
Name[sr@ijekavianlatin]=Virtuelne površi
|
||||||
|
Name[sr@latin]=Virtuelne površi
|
||||||
|
Name[sv]=Virtuella skrivbord
|
||||||
|
Name[tg]=Мизҳои кории виртуалӣ
|
||||||
|
Name[th]=พื้นที่ทำงานเสมือน
|
||||||
|
Name[tr]=Sanal Masaüstleri
|
||||||
|
Name[ug]=مەۋھۇم ئۈستەلئۈستى
|
||||||
|
Name[uk]=Віртуальні стільниці
|
||||||
|
Name[wa]=Forveyous scribannes
|
||||||
|
Name[x-test]=xxVirtual Desktopsxx
|
||||||
|
Name[zh_CN]=虚拟桌面
|
||||||
|
Name[zh_TW]=虛擬桌面
|
||||||
|
|
||||||
|
Comment=Navigation, Number and Layout of Virtual Desktops
|
||||||
|
Comment[bs]=Navigacija, broj i izgled virtualnih desktopa
|
||||||
|
Comment[ca]=Navegació, nombre i disposició dels escriptoris virtuals
|
||||||
|
Comment[ca@valencia]=Navegació, nombre i disposició dels escriptoris virtuals
|
||||||
|
Comment[cs]=Navigace, počet a rozvržení virtuálních ploch
|
||||||
|
Comment[da]=Navigation, antal og layout af virtuelle skriveborde
|
||||||
|
Comment[de]=Navigation, Anzahl und Layout virtueller Arbeitsflächen
|
||||||
|
Comment[el]=Περιήγηση, αριθμός και διάταξη εικονικών επιφανειών εργασίας
|
||||||
|
Comment[en_GB]=Navigation, Number and Layout of Virtual Desktops
|
||||||
|
Comment[es]=Navegación, número y disposición de los escritorios virtuales
|
||||||
|
Comment[et]=Virtuaalsete töölaudade vahel liikumine, nende arv ja paigutus
|
||||||
|
Comment[eu]=Nabigazioa, alegiazko mahaigainen kopurua eta antolamendua
|
||||||
|
Comment[fi]=Virtuaalityöpöytien vaihtaminen, määrä ja asettelu
|
||||||
|
Comment[fr]=Navigation, nombre et disposition des bureaux virtuels
|
||||||
|
Comment[gl]=Navegación, cantidade e disposición dos escritorios virtuais
|
||||||
|
Comment[he]=ניווט, פריסה ומספר שולחנות עבודה וירטואלים
|
||||||
|
Comment[hu]=Navigáció, a virtuális asztalok száma és elrendezése
|
||||||
|
Comment[id]=Navigasi, Jumlah dan Tata Letak Desktop Virtual
|
||||||
|
Comment[it]=Navigazione, numero e disposizione dei desktop virtuali
|
||||||
|
Comment[ko]=가상 데스크톱 탐색, 개수, 레이아웃
|
||||||
|
Comment[lt]=Naršymas, Skaičius ir išdėstymas virtualių darbalaukių
|
||||||
|
Comment[nb]=Navigering, antall og utlegg av virtuelle skrivebord
|
||||||
|
Comment[nds]=Tall, Anornen un dat Anstüern vun de virtuellen Schriefdischen fastleggen
|
||||||
|
Comment[nl]=Navigatie door, aantal en indeling van virtuele bureaubladen
|
||||||
|
Comment[nn]=Navigering, nummer og vising av virtuelle skrivebord
|
||||||
|
Comment[pa]=ਵਰਚੁਅਲ ਡੈਸਕਟਾਪਾਂ ਲਈ ਨੇਵੀਗੇਸ਼ਨ, ਗਿਣਤੀ ਅਤੇ ਢਾਂਚਾ
|
||||||
|
Comment[pl]=Poruszanie się, liczba i układ wirtualnych pulpitów
|
||||||
|
Comment[pt]=Navegação, Número e Disposição dos Ecrãs Virtuais
|
||||||
|
Comment[pt_BR]=Navegação, quantidade e layout das áreas de trabalho virtuais
|
||||||
|
Comment[ru]=Число, расположение и способ переключения рабочих столов
|
||||||
|
Comment[sk]=Navigácia, počet a rozloženie virtuálnych plôch
|
||||||
|
Comment[sl]=Krmarjenje med, število in razporeditev navideznih namizij
|
||||||
|
Comment[sr]=Кретање, број и распоред виртуелних површи
|
||||||
|
Comment[sr@ijekavian]=Кретање, број и распоред виртуелних површи
|
||||||
|
Comment[sr@ijekavianlatin]=Kretanje, broj i raspored virtuelnih površi
|
||||||
|
Comment[sr@latin]=Kretanje, broj i raspored virtuelnih površi
|
||||||
|
Comment[sv]=Navigering, antal och layout av virtuella skrivbord
|
||||||
|
Comment[tr]=Gezinti, Sanal Masaüstlerinin Sayısı ve Yerleşimi
|
||||||
|
Comment[uk]=Навігація, кількість та компонування віртуальних стільниць
|
||||||
|
Comment[vi]=Số lượng, bố trí và điều hướng của màn hình ảo
|
||||||
|
Comment[x-test]=xxNavigation, Number and Layout of Virtual Desktopsxx
|
||||||
|
Comment[zh_CN]=虚拟桌面的切换,数量和布局
|
||||||
|
Comment[zh_TW]=虛擬桌面的導覽、數字與佈局
|
||||||
|
|
||||||
|
Icon=preferences-desktop
|
||||||
|
Type=Service
|
||||||
|
X-KDE-PluginInfo-License=GPL
|
||||||
|
X-KDE-PluginInfo-Name=kcm_kwin_virtualdesktops
|
||||||
|
X-KDE-ServiceTypes=Plasma/Generic
|
||||||
|
X-Plasma-API=declarativeappletscript
|
||||||
|
|
||||||
|
X-Plasma-MainScript=ui/main.qml
|
205
kcmkwin/kwindesktop/virtualdesktops.cpp
Normal file
205
kcmkwin/kwindesktop/virtualdesktops.cpp
Normal file
|
@ -0,0 +1,205 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Eike Hein <hein@kde.org>
|
||||||
|
*
|
||||||
|
* 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 2 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "virtualdesktops.h"
|
||||||
|
#include "desktopsmodel.h"
|
||||||
|
|
||||||
|
#include <KAboutData>
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KLocalizedString>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
|
||||||
|
K_PLUGIN_FACTORY_WITH_JSON(VirtualDesktopsFactory, "kcm_kwin_virtualdesktops.json", registerPlugin<KWin::VirtualDesktops>();)
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
VirtualDesktops::VirtualDesktops(QObject *parent, const QVariantList &args)
|
||||||
|
: KQuickAddons::ConfigModule(parent, args)
|
||||||
|
, m_kwinConfig(KSharedConfig::openConfig("kwinrc"))
|
||||||
|
, m_desktopsModel(new KWin::DesktopsModel(this))
|
||||||
|
, m_navWraps(true)
|
||||||
|
, m_osdEnabled(false)
|
||||||
|
, m_osdDuration(1000)
|
||||||
|
, m_osdTextOnly(false)
|
||||||
|
{
|
||||||
|
KAboutData *about = new KAboutData(QStringLiteral("kcm_kwin_virtualdesktops"),
|
||||||
|
i18n("Configure Virtual Desktops"),
|
||||||
|
QStringLiteral("2.0"), QString(), KAboutLicense::GPL);
|
||||||
|
setAboutData(about);
|
||||||
|
|
||||||
|
setButtons(Apply | Default);
|
||||||
|
|
||||||
|
QObject::connect(m_desktopsModel, &KWin::DesktopsModel::userModifiedChanged,
|
||||||
|
this, &VirtualDesktops::updateNeedsSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDesktops::~VirtualDesktops()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QAbstractItemModel *VirtualDesktops::desktopsModel() const
|
||||||
|
{
|
||||||
|
return m_desktopsModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VirtualDesktops::navWraps() const
|
||||||
|
{
|
||||||
|
return m_navWraps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::setNavWraps(bool wraps)
|
||||||
|
{
|
||||||
|
if (m_navWraps != wraps) {
|
||||||
|
m_navWraps = wraps;
|
||||||
|
|
||||||
|
emit navWrapsChanged();
|
||||||
|
|
||||||
|
updateNeedsSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VirtualDesktops::osdEnabled() const
|
||||||
|
{
|
||||||
|
return m_osdEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::setOsdEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (m_osdEnabled != enabled) {
|
||||||
|
m_osdEnabled = enabled;
|
||||||
|
|
||||||
|
emit osdEnabledChanged();
|
||||||
|
|
||||||
|
updateNeedsSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int VirtualDesktops::osdDuration() const
|
||||||
|
{
|
||||||
|
return m_osdDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::setOsdDuration(int duration)
|
||||||
|
{
|
||||||
|
if (m_osdDuration != duration) {
|
||||||
|
m_osdDuration = duration;
|
||||||
|
|
||||||
|
emit osdDurationChanged();
|
||||||
|
|
||||||
|
updateNeedsSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int VirtualDesktops::osdTextOnly() const
|
||||||
|
{
|
||||||
|
return m_osdTextOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::setOsdTextOnly(bool textOnly)
|
||||||
|
{
|
||||||
|
if (m_osdTextOnly != textOnly) {
|
||||||
|
m_osdTextOnly = textOnly;
|
||||||
|
|
||||||
|
emit osdTextOnlyChanged();
|
||||||
|
|
||||||
|
updateNeedsSave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::load()
|
||||||
|
{
|
||||||
|
KConfigGroup navConfig(m_kwinConfig, "Windows");
|
||||||
|
setNavWraps(navConfig.readEntry<bool>("RollOverDesktops", true));
|
||||||
|
|
||||||
|
KConfigGroup osdConfig(m_kwinConfig, "Plugins");
|
||||||
|
setOsdEnabled(osdConfig.readEntry("desktopchangeosdEnabled", false));
|
||||||
|
|
||||||
|
KConfigGroup osdSettings(m_kwinConfig, "Script-desktopchangeosd");
|
||||||
|
setOsdDuration(osdSettings.readEntry("PopupHideDelay", 1000));
|
||||||
|
setOsdTextOnly(osdSettings.readEntry("TextOnly", false));
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::save()
|
||||||
|
{
|
||||||
|
m_desktopsModel->syncWithServer();
|
||||||
|
|
||||||
|
KConfigGroup navConfig(m_kwinConfig, "Windows");
|
||||||
|
navConfig.writeEntry("RollOverDesktops", m_navWraps);
|
||||||
|
|
||||||
|
KConfigGroup osdConfig(m_kwinConfig, "Plugins");
|
||||||
|
osdConfig.writeEntry("desktopchangeosdEnabled", m_osdEnabled);
|
||||||
|
|
||||||
|
KConfigGroup osdSettings(m_kwinConfig, "Script-desktopchangeosd");
|
||||||
|
osdSettings.writeEntry("PopupHideDelay", m_osdDuration);
|
||||||
|
osdSettings.writeEntry("TextOnly", m_osdTextOnly);
|
||||||
|
|
||||||
|
m_kwinConfig->sync();
|
||||||
|
|
||||||
|
QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KWin"),
|
||||||
|
QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"));
|
||||||
|
QDBusConnection::sessionBus().send(message);
|
||||||
|
|
||||||
|
setNeedsSave(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::defaults()
|
||||||
|
{
|
||||||
|
m_desktopsModel->setRows(1);
|
||||||
|
|
||||||
|
setNavWraps(true);
|
||||||
|
setOsdEnabled(false);
|
||||||
|
setOsdDuration(1000);
|
||||||
|
setOsdTextOnly(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDesktops::updateNeedsSave()
|
||||||
|
{
|
||||||
|
bool needsSave = false;
|
||||||
|
|
||||||
|
if (m_desktopsModel->userModified()) {
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
KConfigGroup navConfig(m_kwinConfig, "Windows");
|
||||||
|
|
||||||
|
if (m_navWraps != navConfig.readEntry<bool>("RollOverDesktops", true)) {
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
KConfigGroup osdConfig(m_kwinConfig, "Plugins");
|
||||||
|
|
||||||
|
if (m_osdEnabled != osdConfig.readEntry("desktopchangeosdEnabled", false)) {
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
KConfigGroup osdSettings(m_kwinConfig, "Script-desktopchangeosd");
|
||||||
|
|
||||||
|
if (m_osdDuration != osdSettings.readEntry("PopupHideDelay", 1000)) {
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_osdTextOnly != osdSettings.readEntry("TextOnly", false)) {
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setNeedsSave(needsSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "virtualdesktops.moc"
|
82
kcmkwin/kwindesktop/virtualdesktops.h
Normal file
82
kcmkwin/kwindesktop/virtualdesktops.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Eike Hein <hein@kde.org>
|
||||||
|
*
|
||||||
|
* 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 2 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VIRTUALDESKTOPS_H
|
||||||
|
#define VIRTUALDESKTOPS_H
|
||||||
|
|
||||||
|
#include <KQuickAddons/ConfigModule>
|
||||||
|
#include <KSharedConfig>
|
||||||
|
|
||||||
|
namespace KWin
|
||||||
|
{
|
||||||
|
|
||||||
|
class DesktopsModel;
|
||||||
|
|
||||||
|
class VirtualDesktops : public KQuickAddons::ConfigModule
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QAbstractItemModel* desktopsModel READ desktopsModel CONSTANT)
|
||||||
|
Q_PROPERTY(bool navWraps READ navWraps WRITE setNavWraps NOTIFY navWrapsChanged)
|
||||||
|
Q_PROPERTY(bool osdEnabled READ osdEnabled WRITE setOsdEnabled NOTIFY osdEnabledChanged)
|
||||||
|
Q_PROPERTY(int osdDuration READ osdDuration WRITE setOsdDuration NOTIFY osdDurationChanged)
|
||||||
|
Q_PROPERTY(bool osdTextOnly READ osdTextOnly WRITE setOsdTextOnly NOTIFY osdTextOnlyChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit VirtualDesktops(QObject *parent = nullptr, const QVariantList &list = QVariantList());
|
||||||
|
~VirtualDesktops() override;
|
||||||
|
|
||||||
|
QAbstractItemModel *desktopsModel() const;
|
||||||
|
|
||||||
|
bool navWraps() const;
|
||||||
|
void setNavWraps(bool wraps);
|
||||||
|
|
||||||
|
bool osdEnabled() const;
|
||||||
|
void setOsdEnabled(bool enabled);
|
||||||
|
|
||||||
|
int osdDuration() const;
|
||||||
|
void setOsdDuration(int duration);
|
||||||
|
|
||||||
|
int osdTextOnly() const;
|
||||||
|
void setOsdTextOnly(bool textOnly);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void navWrapsChanged() const;
|
||||||
|
void osdEnabledChanged() const;
|
||||||
|
void osdDurationChanged() const;
|
||||||
|
void osdTextOnlyChanged() const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void load() override;
|
||||||
|
void save() override;
|
||||||
|
void defaults() override;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void updateNeedsSave();
|
||||||
|
|
||||||
|
private:
|
||||||
|
KSharedConfigPtr m_kwinConfig;
|
||||||
|
DesktopsModel *m_desktopsModel;
|
||||||
|
bool m_navWraps;
|
||||||
|
bool m_osdEnabled;
|
||||||
|
int m_osdDuration;
|
||||||
|
bool m_osdTextOnly;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue