diff --git a/CMakeLists.txt b/CMakeLists.txt index d84658b9..29b461d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,8 +272,6 @@ add_subdirectory(kcontrol) add_subdirectory(kmenuedit) add_subdirectory(kinfocenter) -add_subdirectory(kcminit) - if (LightDM_FOUND) add_subdirectory(kgreeter) endif(LightDM_FOUND) diff --git a/kcminit/CMakeLists.txt b/kcminit/CMakeLists.txt deleted file mode 100644 index 8700e79e..00000000 --- a/kcminit/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -########### next target ############### - -add_definitions(-DKDE_DEFAULT_DEBUG_AREA=90250) - -add_executable(kcminit main.cpp) - -target_link_libraries(kcminit - KDE4::kcmutils - KDE4::kdeui - ${X11_LIBRARIES} -) - -install( - TARGETS kcminit - DESTINATION ${KDE4_BIN_INSTALL_DIR} -) - -# write a cmake script file which creates the symlink -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_kcminit_startup_symlink.cmake - "EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E create_symlink kcminit \"\$ENV{DESTDIR}${KDE4_BIN_INSTALL_DIR}/kcminit_startup\")\n" -) -# and add it as post-install script for kcminit -set_target_properties(kcminit PROPERTIES - POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_kcminit_startup_symlink.cmake -) diff --git a/kcminit/Messages.sh b/kcminit/Messages.sh deleted file mode 100755 index 1458659b..00000000 --- a/kcminit/Messages.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -$XGETTEXT *.cpp -o $podir/kcminit.pot diff --git a/kcminit/main.cpp b/kcminit/main.cpp deleted file mode 100644 index e77ea015..00000000 --- a/kcminit/main.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* - Copyright (c) 1999 Matthias Hoelzer-Kluepfel - - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ - -#include - -#include "main.h" - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_WS_X11 -#include -#include -#endif - -static int ready[ 2 ]; -static bool startup = false; - -static void sendReady() -{ - if( ready[ 1 ] == -1 ) - return; - char c = 0; - write( ready[ 1 ], &c, 1 ); - close( ready[ 1 ] ); - ready[ 1 ] = -1; -} - -static void waitForReady() -{ - char c = 1; - close( ready[ 1 ] ); - read( ready[ 0 ], &c, 1 ); - close( ready[ 0 ] ); -} - -bool KCMInit::runModule(const QString &libName, KService::Ptr service) -{ - QLibrary lib(libName); - if (lib.load()) { - QVariant tmp = service->property("X-KDE-Init-Symbol", QVariant::String); - QString kcminit; - if ( tmp.isValid() ) { - kcminit = tmp.toString(); - if( !kcminit.startsWith( QLatin1String( "kcminit_" ) ) ) - kcminit = "kcminit_" + kcminit; - } else { - kcminit = "kcminit_" + libName; - } - - // get the kcminit_ function - void *init = lib.resolve(kcminit.toUtf8()); - if (init) { - // initialize the module - kDebug() << "Initializing " << libName << ": " << kcminit; - - void (*func)() = (void(*)())init; - func(); - return true; - } else { - kDebug() << "Module" << libName << "does not actually have a kcminit function"; - } - } - return false; -} - -void KCMInit::runModules( int phase ) -{ - for(KService::List::Iterator it = list.begin(); - it != list.end(); - ++it) { - KService::Ptr service = (*it); - - QString library = service->library(); - if (library.isEmpty()) { - continue; // Skip - } - - QVariant vphase = service->property("X-KDE-Init-Phase", QVariant::Int ); - int libphase = 1; - if( vphase.isValid() ) - libphase = vphase.toInt(); - - if( phase != -1 && libphase != phase ) - continue; - - // try to load the library - if (!alreadyInitialized.contains(library)) { - runModule(library, service); - alreadyInitialized.append(library); - } - } -} - -KCMInit::KCMInit( KCmdLineArgs* args ) -{ - QDBusConnection::sessionBus().registerObject("/kcminit", this, - QDBusConnection::ExportScriptableSlots|QDBusConnection::ExportScriptableSignals); - QString arg; - if (args->count() == 1) { - arg = args->arg(0); - } - - if (args->isSet("list")) - { - list = KServiceTypeTrader::self()->query( "KCModuleInit" ); - - for(KService::List::Iterator it = list.begin(); - it != list.end(); - ++it) - { - KService::Ptr service = (*it); - if (service->library().isEmpty()) - continue; // Skip - printf("%s\n", QFile::encodeName(service->desktopEntryName()).data()); - } - return; - } - - if (!arg.isEmpty()) { - - QString module = arg; - if (!module.endsWith(".desktop")) - module += ".desktop"; - - KService::Ptr serv = KService::serviceByStorageId( module ); - if ( !serv || serv->library().isEmpty() ) { - kError() << i18n("Module %1 not found", module); - return; - } else - list.append(serv); - - } else { - - // locate the desktop files - list = KServiceTypeTrader::self()->query( "KCModuleInit" ); - - } - - if( startup ) - { - runModules( 0 ); - sendReady(); - QTimer::singleShot( 300 * 1000, qApp, SLOT(quit())); // just in case - qApp->exec(); // wait for runPhase1() and runPhase2() - } - else - runModules( -1 ); // all phases -} - -KCMInit::~KCMInit() -{ - sendReady(); -} - -void KCMInit::runPhase1() -{ - runModules( 1 ); - emit phase1Done(); -} - -void KCMInit::runPhase2() -{ - runModules( 2 ); - emit phase2Done(); - qApp->exit( 0 ); -} - -int main(int argc, char *argv[]) -{ - // during KDE startup only important kcm's are started very early in the login process, - // the rest is delayed, so fork and make parent return after the initial phase - pipe( ready ); - if( fork() != 0 ) - { - waitForReady(); - return 0; - } - close( ready[ 0 ] ); - - startup = ( strcmp( argv[ 0 ], "kcminit_startup" ) == 0 ); // started from startkde? - KAboutData aboutData( "kcminit", "kcminit", ki18n("KCMInit"), - "", - ki18n("KCMInit - runs startup initialization for Control Modules.")); - - KCmdLineArgs::init(argc, argv, &aboutData); - - KCmdLineOptions options; - options.add("list", ki18n("List modules that are run at startup")); - options.add("+module", ki18n("Configuration module to run")); - KCmdLineArgs::addCmdLineOptions( options ); // Add our own options. - - KApplication app; - QDBusConnection::sessionBus().interface()->registerService( "org.kde.kcminit", - QDBusConnectionInterface::DontQueueService ); - KCMInit kcminit( KCmdLineArgs::parsedArgs()); - return 0; -} - -#include "moc_main.cpp" diff --git a/kcminit/main.h b/kcminit/main.h deleted file mode 100644 index 51358bb4..00000000 --- a/kcminit/main.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - Copyright (c) 1999 Matthias Hoelzer-Kluepfel - - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ - -#ifndef MAIN_H -#define MAIN_H - -#include - -class KCmdLineArgs; - -class KCMInit : public QObject -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "org.kde.KCMInit") - public Q_SLOTS: //dbus - Q_SCRIPTABLE void runPhase1(); - Q_SCRIPTABLE void runPhase2(); - Q_SIGNALS: //dbus signal - Q_SCRIPTABLE void phase1Done(); - Q_SCRIPTABLE void phase2Done(); - public: - KCMInit( KCmdLineArgs* args ); - virtual ~KCMInit(); - private: - bool runModule(const QString &libName, KService::Ptr service); - void runModules( int phase ); - KService::List list; - QStringList alreadyInitialized; -}; - -#endif // MAIN_H diff --git a/kcontrol/desktoppaths/CMakeLists.txt b/kcontrol/desktoppaths/CMakeLists.txt index 64147efc..30559095 100644 --- a/kcontrol/desktoppaths/CMakeLists.txt +++ b/kcontrol/desktoppaths/CMakeLists.txt @@ -1,5 +1,4 @@ set(kcm_desktoppaths_PART_SRCS - globalpaths.cpp kcmdesktoppaths.cpp ) @@ -26,3 +25,20 @@ install( data/Home.desktop DESTINATION ${KDE4_DATA_INSTALL_DIR}/kcm_desktoppaths ) + +########### next target ############### + +add_executable(kdesktoppaths kdesktoppaths.cpp) +target_link_libraries(kdesktoppaths + KDE4::kdecore +) + +install( + TARGETS kdesktoppaths + DESTINATION ${KDE4_BIN_INSTALL_DIR} +) + +install( + FILES kdesktoppaths.desktop + DESTINATION ${KDE4_AUTOSTART_INSTALL_DIR} +) diff --git a/kcontrol/desktoppaths/desktoppath.desktop b/kcontrol/desktoppaths/desktoppath.desktop index 91e2f1d6..2be2d092 100644 --- a/kcontrol/desktoppaths/desktoppath.desktop +++ b/kcontrol/desktoppaths/desktoppath.desktop @@ -1,12 +1,11 @@ [Desktop Entry] Type=Service -X-KDE-ServiceTypes=KCModule,KCModuleInit +X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/paths/index.html Icon=system-file-manager Exec=kcmshell4 desktoppath X-KDE-Library=kcm_desktoppaths -X-KDE-Init-Symbol=kcminit_desktoppaths X-KDE-PluginKeyword=dpath X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=account-details diff --git a/kcontrol/desktoppaths/globalpaths.cpp b/kcontrol/desktoppaths/globalpaths.cpp deleted file mode 100644 index 04bff653..00000000 --- a/kcontrol/desktoppaths/globalpaths.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/** - * Copyright (c) Martin R. Jones 1996 - * Copyright (c) Bernd Wuebben 1998 - * Copyright (c) Christian Tibirna 1998 - * Copyright 1998-2007 David Faure - * Copyright (c) 2010 Matthias Fuchs - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -// -// -// "Desktop Options" Tab for KDesktop configuration -// -// (c) Martin R. Jones 1996 -// (c) Bernd Wuebben 1998 -// -// Layouts -// (c) Christian Tibirna 1998 -// Port to KControl, split from Misc Tab, Port to KControl2 -// (c) David Faure 1998 -// Desktop menus, paths -// (c) David Faure 2000 - - -// Own -#include "globalpaths.h" - -// Qt -#include -#include -#include -#include -#include -#include -#include -#include - -// KDE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kcmdesktoppaths.h" - -//----------------------------------------------------------------------------- - -DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &) - : KCModule( KcmDesktopPaths::componentData(), parent ) -{ - QFormLayout *lay = new QFormLayout(this); - lay->setMargin(0); - - setQuickHelp( i18n("

Paths

\n" - "This module allows you to choose where in the filesystem the " - "files on your desktop should be stored.\n" - "Use the \"Whats This?\" (Shift+F1) to get help on specific options.")); - - urDesktop = addRow(lay, i18n("Desktop path:"), - i18n("This folder contains all the files" - " which you see on your desktop. You can change the location of this" - " folder if you want to, and the contents will move automatically" - " to the new location as well.")); - - urDocument = addRow(lay, i18n("Documents path:"), - i18n("This folder will be used by default to " - "load or save documents from or to.")); - - urDownload = addRow(lay, i18n("Downloads path:"), - i18n("This folder will be used by default to " - "save your downloaded items.")); - - urMovie = addRow(lay, i18n("Movies path:"), - i18n("This folder will be used by default to " - "load or save movies from or to.")); - - urPicture = addRow(lay, i18n("Pictures path:"), - i18n("This folder will be used by default to " - "load or save pictures from or to.")); - - urMusic = addRow(lay, i18n("Music path:"), - i18n("This folder will be used by default to " - "load or save music from or to.")); -} - -KUrlRequester* DesktopPathConfig::addRow(QFormLayout *lay, const QString& label, const QString& whatsThis) -{ - KUrlRequester* ur = new KUrlRequester(this); - ur->setMode(KFile::Directory | KFile::LocalOnly); - lay->addRow(label, ur); - connect(ur, SIGNAL(textChanged(QString)), this, SLOT(changed())); - lay->labelForField(ur)->setWhatsThis(whatsThis); - ur->setWhatsThis(whatsThis); - return ur; -} - -void DesktopPathConfig::load() -{ - // Desktop Paths - urDesktop->setUrl( KGlobalSettings::desktopPath() ); - urDocument->setUrl( KGlobalSettings::documentPath() ); - urDownload->setUrl( KGlobalSettings::downloadPath() ); - urMovie->setUrl( KGlobalSettings::videosPath() ); - urPicture->setUrl( KGlobalSettings::picturesPath() ); - urMusic->setUrl( KGlobalSettings::musicPath() ); - emit changed(false); -} - -void DesktopPathConfig::defaults() -{ - // Desktop Paths - keep defaults in sync with kglobalsettings.cpp - urDesktop->setUrl( QString(QDir::homePath() + "/Desktop") ); - urDocument->setUrl( QString(QDir::homePath() + "/Documents") ); - urDownload->setUrl( QString(QDir::homePath() + "/Downloads") ); - urMovie->setUrl( QString(QDir::homePath() + "/Movies") ); - urPicture->setUrl( QString(QDir::homePath() + "/Pictures") ); - urMusic->setUrl( QString(QDir::homePath() + "/Music") ); -} - -// the following method is copied from kdelibs/kdecore/config/kconfiggroup.cpp -static bool cleanHomeDirPath( QString &path, const QString &homeDir ) -{ - if (!path.startsWith(homeDir)) - return false; - - int len = homeDir.length(); - // replace by "$HOME" if possible - if (len && (path.length() == len || path[len] == '/')) { - path.replace(0, len, QString::fromLatin1("$HOME")); - return true; - } else - return false; -} - -// TODO this functionality is duplicated in libkonq - keep it only there and export - -static QString translatePath( QString path ) // krazy:exclude=passbyvalue -{ - // keep only one single '/' at the beginning - needed for cleanHomeDirPath() - while (path[0] == '/' && path[1] == '/') - path.remove(0,1); - - // we probably should escape any $ ` and \ characters that may occur in the path, but the Qt code that reads back - // the file doesn't unescape them so not much point in doing so - - // All of the 3 following functions to return the user's home directory - // can return different paths. We have to test all them. - const QString homeDir0 = QFile::decodeName(qgetenv("HOME")); - const QString homeDir1 = QDir::homePath(); - const QString homeDir2 = QDir(homeDir1).canonicalPath(); - if (cleanHomeDirPath(path, homeDir0) || - cleanHomeDirPath(path, homeDir1) || - cleanHomeDirPath(path, homeDir2) ) { - // kDebug() << "Path was replaced\n"; - } - - return path; -} - -void DesktopPathConfig::save() -{ - KSharedConfig::Ptr config = KGlobal::config(); - KConfigGroup configGroup( config, "Paths" ); - - bool pathChanged = false; - - KUrl desktopURL( KGlobalSettings::desktopPath() ); - - if ( !urDesktop->url().equals( desktopURL, KUrl::RemoveTrailingSlash ) ) - { - // Test which other paths were inside this one (as it is by default) - // and for each, test where it should go. - // * Inside destination -> let them be moved with the desktop (but adjust name if necessary) - // * Not inside destination -> move first - // !!! - kDebug() << "desktopURL=" << desktopURL; - QString urlDesktop = urDesktop->url().toLocalFile(); - if ( !urlDesktop.endsWith('/')) - urlDesktop+='/'; - - if ( moveDir( KUrl( KGlobalSettings::desktopPath() ), KUrl( urlDesktop ), i18n("Desktop") ) ) - { - //save in XDG path - const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); - KConfig xdgUserConf( userDirsFile, KConfig::SimpleConfig ); - KConfigGroup g( &xdgUserConf, "" ); - g.writeEntry( "XDG_DESKTOP_DIR", QString("\"" + translatePath( urlDesktop ) + "\"") ); - pathChanged = true; - } - } - - config->sync(); - - if (xdgSavePath(urDocument, KGlobalSettings::documentPath(), "XDG_DOCUMENTS_DIR", i18n("Documents"))) - pathChanged = true; - - if (xdgSavePath(urDownload, KGlobalSettings::downloadPath(), "XDG_DOWNLOAD_DIR", i18n("Downloads"))) - pathChanged = true; - - if (xdgSavePath(urMovie, KGlobalSettings::videosPath(), "XDG_VIDEOS_DIR", i18n("Movies"))) - pathChanged = true; - - if (xdgSavePath(urPicture, KGlobalSettings::picturesPath(), "XDG_PICTURES_DIR", i18n("Pictures"))) - pathChanged = true; - - if (xdgSavePath(urMusic, KGlobalSettings::musicPath(), "XDG_MUSIC_DIR", i18n("Music"))) - pathChanged = true; - - if (pathChanged) { - kDebug() << "sending message SettingsChanged"; - KGlobalSettings::self()->emitChange(KGlobalSettings::PathsChanged); - } -} - -bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type) -{ - KUrl newUrl = ur->url(); - //url might be empty, use QDir::homePath (the default for xdg) then - if (!newUrl.isValid()) { - newUrl = KUrl(QDir::homePath()); - } - if (!newUrl.equals(currentUrl, KUrl::RemoveTrailingSlash)) { - const QString path = newUrl.toLocalFile(); - if (!QDir(path).exists()) { - // Check permissions - if (KStandardDirs::makeDir(path)) { - QDir().rmdir(path); // rmdir again, so that we get a fast rename - } else { - KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_COULD_NOT_MKDIR, path)); - ur->setUrl(currentUrl); // revert - return false; - } - } - if (moveDir(currentUrl, newUrl, type)) { - //save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QStandardPaths reads from. - const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); - KConfig xdgUserConf(userDirsFile, KConfig::SimpleConfig); - KConfigGroup g(&xdgUserConf, ""); - g.writeEntry(xdgKey, QString("\"" + translatePath(path) + "\"")); - return true; - } - } - return false; -} - -bool DesktopPathConfig::moveDir( const KUrl & src, const KUrl & dest, const QString & type ) -{ - if (!src.isLocalFile() || !dest.isLocalFile()) - return true; - if (!QDir(src.toLocalFile()).exists()) - return true; - // Do not move $HOME! #193057 - const QString translatedPath = translatePath(src.toLocalFile()); - if (translatedPath == "$HOME" || translatedPath == "$HOME/") { - return true; - } - - m_ok = true; - - QString question; - KGuiItem yesItem; - KGuiItem noItem; - const bool destExists = QDir(dest.toLocalFile()).exists(); - if (destExists) { - // TODO: check if the src dir is empty? Nothing to move, then... - question = i18n("The path for '%1' has been changed.\nDo you want the files to be moved from '%2' to '%3'?", - type, src.toLocalFile(), - dest.toLocalFile()); - yesItem = KGuiItem(i18nc("Move files from old to new place", "Move")); - noItem = KGuiItem(i18nc("Use the new directory but do not move files", "Do not Move")); - } else { - question = i18n("The path for '%1' has been changed.\nDo you want to move the directory '%2' to '%3'?", - type, src.toLocalFile(), - dest.toLocalFile()); - yesItem = KGuiItem(i18nc("Move the directory", "Move")); - noItem = KGuiItem(i18nc("Use the new directory but do not move anything", "Do not Move")); - } - - // Ask for confirmation before moving the files - if (KMessageBox::questionYesNo(this, question, i18n("Confirmation Required"), - yesItem, noItem) - == KMessageBox::Yes ) - { - if (destExists) { - // Destination already exists -- should always be the case, for most types, - // but maybe not for the complex autostart case (to be checked...) - m_copyToDest = dest; - m_copyFromSrc = src; - KIO::ListJob* job = KIO::listDir( src ); - job->setAutoDelete(false); // see below - job->ui()->setWindow(this); - job->ui()->setAutoErrorHandlingEnabled(true); - connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), - this, SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList))); - // slotEntries will move every file/subdir individually into the dest - job->exec(); - if (m_ok) { - QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now - } - delete job; - } - else - { - kDebug() << "Direct move from" << src << "to" << dest; - KIO::Job * job = KIO::move( src, dest ); - job->ui()->setWindow(this); - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); - job->exec(); - } - } - kDebug() << "DesktopPathConfig::slotResult returning " << m_ok; - return m_ok; -} - -void DesktopPathConfig::slotEntries(KIO::Job*, const KIO::UDSEntryList& list) -{ - QListIterator it(list); - while (it.hasNext()) { - KFileItem file(it.next(), m_copyFromSrc, true, true); - kDebug() << file.url(); - if (file.url() == m_copyFromSrc || file.url().fileName() == "..") { - continue; - } - - KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest); - moveJob->ui()->setWindow(this); - connect(moveJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); - moveJob->exec(); // sub-event loop here. : the main job is not autodeleted because it would be deleted here - } -} - -void DesktopPathConfig::slotResult( KJob * job ) -{ - if (job->error()) { - if ( job->error() != KIO::ERR_DOES_NOT_EXIST ) - m_ok = false; - - // If the source doesn't exist, no wonder we couldn't move the dir. - // In that case, trust the user and set the new setting in any case. - - static_cast(job)->ui()->showErrorMessage(); - } -} - -#include "moc_globalpaths.cpp" diff --git a/kcontrol/desktoppaths/globalpaths.h b/kcontrol/desktoppaths/globalpaths.h deleted file mode 100644 index b27224e9..00000000 --- a/kcontrol/desktoppaths/globalpaths.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright (c) Martin R. Jones 1996 - * Copyright 1998-2007 David Faure - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -// Summarized history: -// -// "Desktop Icons Options" Tab for KDesktop configuration -// Martin Jones -// -// Port to KControl, split from "Misc" Tab, Port to KControl2 -// (c) David Faure 1998 -// Desktop menus, paths -// (c) David Faure 2000 - -#ifndef GLOBALPATHS_H -#define GLOBALPATHS_H - -#include -#include -#include -#include - -#include -class KJob; -class KUrlRequester; -#include - -namespace KIO { class Job; } - -//----------------------------------------------------------------------------- -// The "Path" Tab contains : -// The paths for Desktop, Autostart and Documents - -class DesktopPathConfig : public KCModule -{ - Q_OBJECT -public: - DesktopPathConfig( QWidget *parent, const QVariantList &args ); - virtual void load(); - virtual void save(); - virtual void defaults(); - -private Q_SLOTS: - void slotEntries( KIO::Job * job, const KIO::UDSEntryList& list); - -private: - KUrlRequester* addRow(QFormLayout *lay, const QString& label, const QString& whatsThis); - bool xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type); - - // Desktop Paths - KUrlRequester *urDesktop; - KUrlRequester *urDocument; - KUrlRequester *urDownload; - KUrlRequester *urMovie; - KUrlRequester *urPicture; - KUrlRequester *urMusic; - - bool moveDir( const KUrl & src, const KUrl & dest, const QString & type ); - bool m_ok; - KUrl m_copyToDest; // used when the destination directory already exists - KUrl m_copyFromSrc; - -private Q_SLOTS: - void slotResult( KJob * job ); -}; - -#endif - diff --git a/kcontrol/desktoppaths/kcmdesktoppaths.cpp b/kcontrol/desktoppaths/kcmdesktoppaths.cpp index cb10b1b3..f60c8ebc 100644 --- a/kcontrol/desktoppaths/kcmdesktoppaths.cpp +++ b/kcontrol/desktoppaths/kcmdesktoppaths.cpp @@ -1,71 +1,373 @@ -/* This file is part of the KDE project - Copyright (C) 2006-2007 Matthias Kretz +/** + * Copyright (c) Martin R. Jones 1996 + * Copyright (c) Bernd Wuebben 1998 + * Copyright (c) Christian Tibirna 1998 + * Copyright 1998-2007 David Faure + * Copyright (c) 2010 Matthias Fuchs + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. +// +// +// "Desktop Options" Tab for KDesktop configuration +// +// (c) Martin R. Jones 1996 +// (c) Bernd Wuebben 1998 +// +// Layouts +// (c) Christian Tibirna 1998 +// Port to KControl, split from Misc Tab, Port to KControl2 +// (c) David Faure 1998 +// Desktop menus, paths +// (c) David Faure 2000 - 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. +// Own +#include "kcmdesktoppaths.h" -*/ +// Katie +#include +#include +#include +#include +#include +#include +#include +#include + +// KDE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "kcmdesktoppaths.h" -#include "globalpaths.h" -#include -#include -#include -#include -#include - -#include +//----------------------------------------------------------------------------- +K_PLUGIN_FACTORY_DECLARATION(KcmDesktopPaths) K_PLUGIN_FACTORY_DEFINITION(KcmDesktopPaths, registerPlugin("dpath");) K_EXPORT_PLUGIN(KcmDesktopPaths("kcm_desktoppaths")) -extern "C" +DesktopPathConfig::DesktopPathConfig(QWidget *parent, const QVariantList &) + : KCModule( KcmDesktopPaths::componentData(), parent ) { - Q_DECL_EXPORT void kcminit_desktoppaths() + QFormLayout *lay = new QFormLayout(this); + lay->setMargin(0); + + setQuickHelp( i18n("

Paths

\n" + "This module allows you to choose where in the filesystem the " + "files on your desktop should be stored.\n" + "Use the \"Whats This?\" (Shift+F1) to get help on specific options.")); + + urDesktop = addRow(lay, i18n("Desktop path:"), + i18n("This folder contains all the files" + " which you see on your desktop. You can change the location of this" + " folder if you want to, and the contents will move automatically" + " to the new location as well.")); + + urDocument = addRow(lay, i18n("Documents path:"), + i18n("This folder will be used by default to " + "load or save documents from or to.")); + + urDownload = addRow(lay, i18n("Downloads path:"), + i18n("This folder will be used by default to " + "save your downloaded items.")); + + urMovie = addRow(lay, i18n("Movies path:"), + i18n("This folder will be used by default to " + "load or save movies from or to.")); + + urPicture = addRow(lay, i18n("Pictures path:"), + i18n("This folder will be used by default to " + "load or save pictures from or to.")); + + urMusic = addRow(lay, i18n("Music path:"), + i18n("This folder will be used by default to " + "load or save music from or to.")); +} + +KUrlRequester* DesktopPathConfig::addRow(QFormLayout *lay, const QString& label, const QString& whatsThis) +{ + KUrlRequester* ur = new KUrlRequester(this); + ur->setMode(KFile::Directory | KFile::LocalOnly); + lay->addRow(label, ur); + connect(ur, SIGNAL(textChanged(QString)), this, SLOT(changed())); + lay->labelForField(ur)->setWhatsThis(whatsThis); + ur->setWhatsThis(whatsThis); + return ur; +} + +void DesktopPathConfig::load() +{ + // Desktop Paths + urDesktop->setUrl( KGlobalSettings::desktopPath() ); + urDocument->setUrl( KGlobalSettings::documentPath() ); + urDownload->setUrl( KGlobalSettings::downloadPath() ); + urMovie->setUrl( KGlobalSettings::videosPath() ); + urPicture->setUrl( KGlobalSettings::picturesPath() ); + urMusic->setUrl( KGlobalSettings::musicPath() ); + emit changed(false); +} + +void DesktopPathConfig::defaults() +{ + // Desktop Paths - keep defaults in sync with kglobalsettings.cpp + urDesktop->setUrl( QString(QDir::homePath() + "/Desktop") ); + urDocument->setUrl( QString(QDir::homePath() + "/Documents") ); + urDownload->setUrl( QString(QDir::homePath() + "/Downloads") ); + urMovie->setUrl( QString(QDir::homePath() + "/Movies") ); + urPicture->setUrl( QString(QDir::homePath() + "/Pictures") ); + urMusic->setUrl( QString(QDir::homePath() + "/Music") ); +} + +// the following method is copied from kdelibs/kdecore/config/kconfiggroup.cpp +static bool cleanHomeDirPath( QString &path, const QString &homeDir ) +{ + if (!path.startsWith(homeDir)) + return false; + + int len = homeDir.length(); + // replace by "$HOME" if possible + if (len && (path.length() == len || path[len] == '/')) { + path.replace(0, len, QString::fromLatin1("$HOME")); + return true; + } else + return false; +} + +// TODO this functionality is duplicated in libkonq - keep it only there and export + +static QString translatePath( QString path ) // krazy:exclude=passbyvalue +{ + // keep only one single '/' at the beginning - needed for cleanHomeDirPath() + while (path[0] == '/' && path[1] == '/') + path.remove(0,1); + + // we probably should escape any $ ` and \ characters that may occur in the path, but the Qt code that reads back + // the file doesn't unescape them so not much point in doing so + + // All of the 3 following functions to return the user's home directory + // can return different paths. We have to test all them. + const QString homeDir0 = QFile::decodeName(qgetenv("HOME")); + const QString homeDir1 = QDir::homePath(); + const QString homeDir2 = QDir(homeDir1).canonicalPath(); + if (cleanHomeDirPath(path, homeDir0) || + cleanHomeDirPath(path, homeDir1) || + cleanHomeDirPath(path, homeDir2) ) { + // kDebug() << "Path was replaced\n"; + } + + return path; +} + +void DesktopPathConfig::save() +{ + KSharedConfig::Ptr config = KGlobal::config(); + KConfigGroup configGroup( config, "Paths" ); + + bool pathChanged = false; + + KUrl desktopURL( KGlobalSettings::desktopPath() ); + + if ( !urDesktop->url().equals( desktopURL, KUrl::RemoveTrailingSlash ) ) { - // We can't use KGlobalSettings::desktopPath() here, since it returns the home dir - // if the desktop folder doesn't exist. - QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - if (desktopPath.isEmpty()) { - desktopPath = QDir::homePath() + "/Desktop"; - } + // Test which other paths were inside this one (as it is by default) + // and for each, test where it should go. + // * Inside destination -> let them be moved with the desktop (but adjust name if necessary) + // * Not inside destination -> move first + // !!! + kDebug() << "desktopURL=" << desktopURL; + QString urlDesktop = urDesktop->url().toLocalFile(); + if ( !urlDesktop.endsWith('/')) + urlDesktop+='/'; - // Create the desktop folder if it doesn't exist - bool desktopIsEmpty = false; - const QDir desktopDir(desktopPath); - if (!desktopDir.exists()) { - ::mkdir(QFile::encodeName(desktopPath), S_IRWXU); - desktopIsEmpty = true; - } else { - desktopIsEmpty = desktopDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).isEmpty(); - } - - if (desktopIsEmpty) { - // Copy the desktop links and .directory file - const QStringList links = KGlobal::dirs()->findAllResources("data", "kcm_desktoppaths/*", KStandardDirs::NoDuplicates); - foreach (const QString &link, links) { - QString linkname = link.mid(link.lastIndexOf('/')); - // NOTE: special case for the .directory file, it is .desktop file but hidden one - if (linkname.startsWith(QLatin1String("/directory."))) { - linkname = QString::fromLatin1("/.directory"); - // NOTE: .desktop file but extension does not matter and is better chopped - } else if (linkname.endsWith(QLatin1String(".desktop"))) { - linkname.chop(8); - } - QFile::copy(link, desktopPath + linkname); - } + if ( moveDir( KUrl( KGlobalSettings::desktopPath() ), KUrl( urlDesktop ), i18n("Desktop") ) ) + { + //save in XDG path + const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); + KConfig xdgUserConf( userDirsFile, KConfig::SimpleConfig ); + KConfigGroup g( &xdgUserConf, "" ); + g.writeEntry( "XDG_DESKTOP_DIR", QString("\"" + translatePath( urlDesktop ) + "\"") ); + pathChanged = true; } } + + config->sync(); + + if (xdgSavePath(urDocument, KGlobalSettings::documentPath(), "XDG_DOCUMENTS_DIR", i18n("Documents"))) + pathChanged = true; + + if (xdgSavePath(urDownload, KGlobalSettings::downloadPath(), "XDG_DOWNLOAD_DIR", i18n("Downloads"))) + pathChanged = true; + + if (xdgSavePath(urMovie, KGlobalSettings::videosPath(), "XDG_VIDEOS_DIR", i18n("Movies"))) + pathChanged = true; + + if (xdgSavePath(urPicture, KGlobalSettings::picturesPath(), "XDG_PICTURES_DIR", i18n("Pictures"))) + pathChanged = true; + + if (xdgSavePath(urMusic, KGlobalSettings::musicPath(), "XDG_MUSIC_DIR", i18n("Music"))) + pathChanged = true; + + if (pathChanged) { + kDebug() << "sending message SettingsChanged"; + KGlobalSettings::self()->emitChange(KGlobalSettings::PathsChanged); + } } + +bool DesktopPathConfig::xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type) +{ + KUrl newUrl = ur->url(); + //url might be empty, use QDir::homePath (the default for xdg) then + if (!newUrl.isValid()) { + newUrl = KUrl(QDir::homePath()); + } + if (!newUrl.equals(currentUrl, KUrl::RemoveTrailingSlash)) { + const QString path = newUrl.toLocalFile(); + if (!QDir(path).exists()) { + // Check permissions + if (KStandardDirs::makeDir(path)) { + QDir().rmdir(path); // rmdir again, so that we get a fast rename + } else { + KMessageBox::sorry(this, KIO::buildErrorString(KIO::ERR_COULD_NOT_MKDIR, path)); + ur->setUrl(currentUrl); // revert + return false; + } + } + if (moveDir(currentUrl, newUrl, type)) { + //save in XDG user-dirs.dirs config file, this is where KGlobalSettings/QStandardPaths reads from. + const QString userDirsFile(KGlobal::dirs()->localxdgconfdir() + QLatin1String("user-dirs.dirs")); + KConfig xdgUserConf(userDirsFile, KConfig::SimpleConfig); + KConfigGroup g(&xdgUserConf, ""); + g.writeEntry(xdgKey, QString("\"" + translatePath(path) + "\"")); + return true; + } + } + return false; +} + +bool DesktopPathConfig::moveDir( const KUrl & src, const KUrl & dest, const QString & type ) +{ + if (!src.isLocalFile() || !dest.isLocalFile()) + return true; + if (!QDir(src.toLocalFile()).exists()) + return true; + // Do not move $HOME! #193057 + const QString translatedPath = translatePath(src.toLocalFile()); + if (translatedPath == "$HOME" || translatedPath == "$HOME/") { + return true; + } + + m_ok = true; + + QString question; + KGuiItem yesItem; + KGuiItem noItem; + const bool destExists = QDir(dest.toLocalFile()).exists(); + if (destExists) { + // TODO: check if the src dir is empty? Nothing to move, then... + question = i18n("The path for '%1' has been changed.\nDo you want the files to be moved from '%2' to '%3'?", + type, src.toLocalFile(), + dest.toLocalFile()); + yesItem = KGuiItem(i18nc("Move files from old to new place", "Move")); + noItem = KGuiItem(i18nc("Use the new directory but do not move files", "Do not Move")); + } else { + question = i18n("The path for '%1' has been changed.\nDo you want to move the directory '%2' to '%3'?", + type, src.toLocalFile(), + dest.toLocalFile()); + yesItem = KGuiItem(i18nc("Move the directory", "Move")); + noItem = KGuiItem(i18nc("Use the new directory but do not move anything", "Do not Move")); + } + + // Ask for confirmation before moving the files + if (KMessageBox::questionYesNo(this, question, i18n("Confirmation Required"), + yesItem, noItem) + == KMessageBox::Yes ) + { + if (destExists) { + // Destination already exists -- should always be the case, for most types, + // but maybe not for the complex autostart case (to be checked...) + m_copyToDest = dest; + m_copyFromSrc = src; + KIO::ListJob* job = KIO::listDir( src ); + job->setAutoDelete(false); // see below + job->ui()->setWindow(this); + job->ui()->setAutoErrorHandlingEnabled(true); + connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), + this, SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList))); + // slotEntries will move every file/subdir individually into the dest + job->exec(); + if (m_ok) { + QDir().rmdir(src.toLocalFile()); // hopefully it's empty by now + } + delete job; + } + else + { + kDebug() << "Direct move from" << src << "to" << dest; + KIO::Job * job = KIO::move( src, dest ); + job->ui()->setWindow(this); + connect(job, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + job->exec(); + } + } + kDebug() << "DesktopPathConfig::slotResult returning " << m_ok; + return m_ok; +} + +void DesktopPathConfig::slotEntries(KIO::Job*, const KIO::UDSEntryList& list) +{ + QListIterator it(list); + while (it.hasNext()) { + KFileItem file(it.next(), m_copyFromSrc, true, true); + kDebug() << file.url(); + if (file.url() == m_copyFromSrc || file.url().fileName() == "..") { + continue; + } + + KIO::Job * moveJob = KIO::move(file.url(), m_copyToDest); + moveJob->ui()->setWindow(this); + connect(moveJob, SIGNAL(result(KJob*)), this, SLOT(slotResult(KJob*))); + moveJob->exec(); // sub-event loop here. : the main job is not autodeleted because it would be deleted here + } +} + +void DesktopPathConfig::slotResult( KJob * job ) +{ + if (job->error()) { + if ( job->error() != KIO::ERR_DOES_NOT_EXIST ) + m_ok = false; + + // If the source doesn't exist, no wonder we couldn't move the dir. + // In that case, trust the user and set the new setting in any case. + + static_cast(job)->ui()->showErrorMessage(); + } +} + +#include "moc_kcmdesktoppaths.cpp" diff --git a/kcontrol/desktoppaths/kcmdesktoppaths.h b/kcontrol/desktoppaths/kcmdesktoppaths.h index 0c6295cb..d358f0d9 100644 --- a/kcontrol/desktoppaths/kcmdesktoppaths.h +++ b/kcontrol/desktoppaths/kcmdesktoppaths.h @@ -1,27 +1,83 @@ -/* This file is part of the KDE project - Copyright (C) 2006-2007 Matthias Kretz +/** + * Copyright (c) Martin R. Jones 1996 + * Copyright 1998-2007 David Faure + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License version 2 as published by the Free Software Foundation. - - 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. - -*/ +// Summarized history: +// +// "Desktop Icons Options" Tab for KDesktop configuration +// Martin Jones +// +// Port to KControl, split from "Misc" Tab, Port to KControl2 +// (c) David Faure 1998 +// Desktop menus, paths +// (c) David Faure 2000 #ifndef KCMDESKTOPPATHS_H #define KCMDESKTOPPATHS_H -#include +#include +#include +#include +#include -K_PLUGIN_FACTORY_DECLARATION(KcmDesktopPaths) +#include +class KJob; +class KUrlRequester; +#include + +namespace KIO { class Job; } + +//----------------------------------------------------------------------------- +// The "Path" Tab contains : +// The paths for Desktop, Autostart and Documents + +class DesktopPathConfig : public KCModule +{ + Q_OBJECT +public: + DesktopPathConfig( QWidget *parent, const QVariantList &args ); + virtual void load(); + virtual void save(); + virtual void defaults(); + +private Q_SLOTS: + void slotEntries( KIO::Job * job, const KIO::UDSEntryList& list); + +private: + KUrlRequester* addRow(QFormLayout *lay, const QString& label, const QString& whatsThis); + bool xdgSavePath(KUrlRequester* ur, const KUrl& currentUrl, const char* xdgKey, const QString& type); + + // Desktop Paths + KUrlRequester *urDesktop; + KUrlRequester *urDocument; + KUrlRequester *urDownload; + KUrlRequester *urMovie; + KUrlRequester *urPicture; + KUrlRequester *urMusic; + + bool moveDir( const KUrl & src, const KUrl & dest, const QString & type ); + bool m_ok; + KUrl m_copyToDest; // used when the destination directory already exists + KUrl m_copyFromSrc; + +private Q_SLOTS: + void slotResult( KJob * job ); +}; + +#endif -#endif // KCMDESKTOPPATHS_H diff --git a/kcontrol/desktoppaths/kdesktoppaths.cpp b/kcontrol/desktoppaths/kdesktoppaths.cpp new file mode 100644 index 00000000..f447a93e --- /dev/null +++ b/kcontrol/desktoppaths/kdesktoppaths.cpp @@ -0,0 +1,65 @@ +/* This file is part of the KDE project + Copyright (C) 2006-2007 Matthias Kretz + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include + +#include + +int main(int argc, char *argv[]) +{ + // application instance for events processing + QCoreApplication app(argc, argv); + + // can't use KGlobalSettings::desktopPath() here, since it returns the home dir + // if the desktop folder doesn't exist. + QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + if (desktopPath.isEmpty()) { + desktopPath = QDir::homePath() + "/Desktop"; + } + + // Create the desktop folder if it doesn't exist + bool desktopIsEmpty = false; + const QDir desktopDir(desktopPath); + if (!desktopDir.exists()) { + ::mkdir(QFile::encodeName(desktopPath), S_IRWXU); + desktopIsEmpty = true; + } else { + desktopIsEmpty = desktopDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).isEmpty(); + } + + if (desktopIsEmpty) { + // Copy the desktop links and .directory file + const QStringList links = KGlobal::dirs()->findAllResources("data", "kcm_desktoppaths/*", KStandardDirs::NoDuplicates); + foreach (const QString &link, links) { + QString linkname = link.mid(link.lastIndexOf('/')); + // NOTE: special case for the .directory file, it is .desktop file but hidden one + if (linkname.startsWith(QLatin1String("/directory."))) { + linkname = QString::fromLatin1("/.directory"); + // NOTE: .desktop file but extension does not matter and is better chopped + } else if (linkname.endsWith(QLatin1String(".desktop"))) { + linkname.chop(8); + } + QFile::copy(link, desktopPath + linkname); + } + } + return 0; +} diff --git a/kcontrol/desktoppaths/kdesktoppaths.desktop b/kcontrol/desktoppaths/kdesktoppaths.desktop new file mode 100644 index 00000000..5891e31a --- /dev/null +++ b/kcontrol/desktoppaths/kdesktoppaths.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Service +Name=KDE Desktop Paths +Exec=kdesktoppaths +Icon=system-file-manager +StartupNotify=false +OnlyShowIn=KDE; +X-KDE-autostart-phase=1 +X-DocPath=kcontrol/paths/index.html diff --git a/kcontrol/input/CMakeLists.txt b/kcontrol/input/CMakeLists.txt index c34c1341..081937fb 100644 --- a/kcontrol/input/CMakeLists.txt +++ b/kcontrol/input/CMakeLists.txt @@ -57,7 +57,13 @@ install( ########### next target ############### -set(kcm_input_PART_SRCS mouse.cpp main.cpp logitechmouse.cpp kmousedlg.ui logitechmouse_base.ui ) +set(kcm_input_PART_SRCS + mouse.cpp + mousesettings.cpp + logitechmouse.cpp + kmousedlg.ui + logitechmouse_base.ui +) kde4_add_plugin(kcm_input ${kcm_input_PART_SRCS}) @@ -101,6 +107,27 @@ install( DESTINATION ${KDE4_PLUGIN_INSTALL_DIR} ) + +########### next target ############### + +add_executable(kmouse + kmouse.cpp + logitechmouse.cpp + mousesettings.cpp + logitechmouse_base.ui +) +target_link_libraries(kmouse + KDE4::kdeui + ${X11_LIBRARIES} +) + +if (LIBUSB_FOUND) + target_link_libraries(kmouse ${LIBUSB_LIBRARIES}) +endif (LIBUSB_FOUND) +if (X11_Xcursor_FOUND) + target_link_libraries(kmouse ${X11_Xcursor_LIB}) +endif (X11_Xcursor_FOUND) + ########### install files ############### install( @@ -117,3 +144,13 @@ install( FILES mouse_new.desktop DESTINATION ${KDE4_DATA_INSTALL_DIR}/solid/actions ) + +install( + TARGETS kmouse + DESTINATION ${KDE4_BIN_INSTALL_DIR} +) + +install( + FILES kmouse.desktop + DESTINATION ${KDE4_AUTOSTART_INSTALL_DIR} +) diff --git a/kcontrol/input/kmouse.cpp b/kcontrol/input/kmouse.cpp new file mode 100644 index 00000000..fab81247 --- /dev/null +++ b/kcontrol/input/kmouse.cpp @@ -0,0 +1,77 @@ +/* + * kmouse.cpp + * + * Copyright (c) 1999 Matthias Hoelzer-Kluepfel + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mousesettings.h" + +#include +#ifdef HAVE_XCURSOR +# include +#endif + +int main(int argc, char *argv[]) +{ + // application instance for QX11Info::display() + QApplication app(argc, argv); + + KConfig *config = new KConfig("kcminputrc", KConfig::NoGlobals); + MouseSettings settings; + settings.load(config); + settings.apply(true); // force + + // NOTE: keep in sync with: + // kcontrol/input/kapplymousetheme.cpp +#ifdef HAVE_XCURSOR + KConfigGroup group = config->group("Mouse"); + const QByteArray theme = group.readEntry("cursorTheme", QByteArray(KDE_DEFAULT_CURSOR_THEME)); + const QByteArray size = group.readEntry("cursorSize", QByteArray()); + + // Apply the KDE cursor theme to ourselves + XcursorSetTheme(QX11Info::display(), theme.constData()); + + if (!size.isEmpty()) { + XcursorSetDefaultSize(QX11Info::display(), size.toUInt()); + } + + // Load the default cursor from the theme and apply it to the root window. + Cursor handle = XcursorLibraryLoadCursor(QX11Info::display(), "left_ptr"); + XDefineCursor(QX11Info::display(), QX11Info::appRootWindow(), handle); + XFreeCursor(QX11Info::display(), handle); // Don't leak the cursor + + // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment + // variables when launching applications. + KToolInvocation::self()->setLaunchEnv("XCURSOR_THEME", theme); + if (!size.isEmpty()) { + KToolInvocation::self()->setLaunchEnv("XCURSOR_SIZE", size); + } +#endif + delete config; + return 0; +} diff --git a/kcontrol/input/kmouse.desktop b/kcontrol/input/kmouse.desktop new file mode 100644 index 00000000..d35d5a06 --- /dev/null +++ b/kcontrol/input/kmouse.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Service +Name=KDE Mouse +Exec=kmouse +Icon=preferences-desktop-mouse +StartupNotify=false +OnlyShowIn=KDE; +X-KDE-autostart-phase=0 +X-DocPath=kcontrol/mouse/index.html diff --git a/kcontrol/input/main.cpp b/kcontrol/input/main.cpp deleted file mode 100644 index 4f71b741..00000000 --- a/kcontrol/input/main.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * main.cpp - * - * Copyright (c) 1999 Matthias Hoelzer-Kluepfel - * - * Requires the Qt widget libraries, available at no cost at - * http://www.troll.no/ - * - * 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include - -#include -#include -#include -#include - -#include "mouse.h" -#include - -#include - -#include -#ifdef HAVE_XCURSOR -# include -#endif - -extern "C" -{ - Q_DECL_EXPORT void kcminit_mouse() - { - KConfig *config = new KConfig("kcminputrc", KConfig::NoGlobals ); - MouseSettings settings; - settings.load(config); - settings.apply(true); // force - - // NOTE: keep in sync with: - // kcontrol/input/kapplymousetheme.cpp -#ifdef HAVE_XCURSOR - KConfigGroup group = config->group("Mouse"); - const QByteArray theme = group.readEntry("cursorTheme", QByteArray(KDE_DEFAULT_CURSOR_THEME)); - const QByteArray size = group.readEntry("cursorSize", QByteArray()); - - // Apply the KDE cursor theme to ourselves - XcursorSetTheme(QX11Info::display(), theme.constData()); - - if (!size.isEmpty()) { - XcursorSetDefaultSize(QX11Info::display(), size.toUInt()); - } - - // Load the default cursor from the theme and apply it to the root window. - Cursor handle = XcursorLibraryLoadCursor(QX11Info::display(), "left_ptr"); - XDefineCursor(QX11Info::display(), QX11Info::appRootWindow(), handle); - XFreeCursor(QX11Info::display(), handle); // Don't leak the cursor - - // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment - // variables when launching applications. - KToolInvocation::self()->setLaunchEnv("XCURSOR_THEME", theme); - if (!size.isEmpty()) { - KToolInvocation::self()->setLaunchEnv("XCURSOR_SIZE", size); - } -#endif - delete config; - } -} - - diff --git a/kcontrol/input/mouse.cpp b/kcontrol/input/mouse.cpp index 3c244712..603bf3ce 100644 --- a/kcontrol/input/mouse.cpp +++ b/kcontrol/input/mouse.cpp @@ -49,11 +49,10 @@ #include #include -#undef Below -#undef Above #include #include #include +#include #include #include @@ -72,11 +71,6 @@ #include #include #include -#include -#include - -#undef Below - K_PLUGIN_FACTORY(MouseConfigFactory, registerPlugin(); // mouse @@ -609,87 +603,6 @@ void MouseConfig::slotHandedChanged(int val){ settings->m_handedNeedsApply = true; } -void MouseSettings::load(KConfig *config) -{ - int accel_num, accel_den, threshold; - double accel; - XGetPointerControl( QX11Info::display(), - &accel_num, &accel_den, &threshold ); - accel = float(accel_num) / float(accel_den); - - // get settings from X server - int h = RIGHT_HANDED; - unsigned char map[20]; - num_buttons = XGetPointerMapping(QX11Info::display(), map, 20); - - handedEnabled = true; - - // ## keep this in sync with KGlobalSettings::mouseSettings - if( num_buttons == 1 ) - { - /* disable button remapping */ - handedEnabled = false; - } - else if( num_buttons == 2 ) - { - if ( (int)map[0] == 1 && (int)map[1] == 2 ) - h = RIGHT_HANDED; - else if ( (int)map[0] == 2 && (int)map[1] == 1 ) - h = LEFT_HANDED; - else - /* custom button setup: disable button remapping */ - handedEnabled = false; - } - else - { - middle_button = (int)map[1]; - if ( (int)map[0] == 1 && (int)map[2] == 3 ) - h = RIGHT_HANDED; - else if ( (int)map[0] == 3 && (int)map[2] == 1 ) - h = LEFT_HANDED; - else - { - /* custom button setup: disable button remapping */ - handedEnabled = false; - } - } - - KConfigGroup group = config->group("Mouse"); - double a = group.readEntry("Acceleration",-1.0); - if (a == -1) - accelRate = accel; - else - accelRate = a; - - int t = group.readEntry("Threshold",-1); - if (t == -1) - thresholdMove = threshold; - else - thresholdMove = t; - - QString key = group.readEntry("MouseButtonMapping"); - if (key == "RightHanded") - handed = RIGHT_HANDED; - else if (key == "LeftHanded") - handed = LEFT_HANDED; -#warning was key == NULL how was this working? is key.isNull() what the coder meant? - else if (key.isNull()) - handed = h; - reverseScrollPolarity = group.readEntry( "ReverseScrollPolarity", false); - m_handedNeedsApply = false; - - // SC/DC/AutoSelect/ChangeCursor - group = config->group("KDE"); - doubleClickInterval = group.readEntry("DoubleClickInterval", 400); - dragStartTime = group.readEntry("StartDragTime", 500); - dragStartDist = group.readEntry("StartDragDist", 4); - wheelScrollLines = group.readEntry("WheelScrollLines", 3); - - singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); - autoSelectDelay = group.readEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY); - changeCursor = group.readEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR); -} - void MouseConfig::slotThreshChanged(int value) { thresh->setSuffix(i18np(" pixel", " pixels", value)); @@ -705,113 +618,6 @@ void MouseConfig::slotWheelScrollLinesChanged(int value) wheelScrollLines->setSuffix(i18np(" line", " lines", value)); } -void MouseSettings::apply(bool force) -{ - XChangePointerControl( QX11Info::display(), - true, true, int(qRound(accelRate*10)), 10, thresholdMove); - - // 256 might seems extreme, but X has already been known to return 32, - // and we don't want to truncate things. Xlib limits the table to 256 bytes, - // so it's a good uper bound.. - unsigned char map[256]; - num_buttons = XGetPointerMapping(QX11Info::display(), map, 256); - - int remap=(num_buttons>=1); - if (handedEnabled && (m_handedNeedsApply || force)) { - if( num_buttons == 1 ) - { - map[0] = (unsigned char) 1; - } - else if( num_buttons == 2 ) - { - if (handed == RIGHT_HANDED) - { - map[0] = (unsigned char) 1; - map[1] = (unsigned char) 3; - } - else - { - map[0] = (unsigned char) 3; - map[1] = (unsigned char) 1; - } - } - else // 3 buttons and more - { - if (handed == RIGHT_HANDED) - { - map[0] = (unsigned char) 1; - map[1] = (unsigned char) middle_button; - map[2] = (unsigned char) 3; - } - else - { - map[0] = (unsigned char) 3; - map[1] = (unsigned char) middle_button; - map[2] = (unsigned char) 1; - } - if( num_buttons >= 5 ) - { - // Apps seem to expect logical buttons 4,5 are the vertical wheel. - // With mice with more than 3 buttons (not including wheel) the physical - // buttons mapped to logical 4,5 may not be physical 4,5 , so keep - // this mapping, only possibly reversing them. - int pos; - for( pos = 0; pos < num_buttons; ++pos ) - if( map[pos] == 4 || map[pos] == 5 ) - break; - if( pos < num_buttons - 1 ) - { - map[pos] = reverseScrollPolarity ? (unsigned char) 5 : (unsigned char) 4; - map[pos+1] = reverseScrollPolarity ? (unsigned char) 4 : (unsigned char) 5; - } - } - } - int retval; - if (remap) - while ((retval=XSetPointerMapping(QX11Info::display(), map, - num_buttons)) == MappingBusy) - /* keep trying until the pointer is free */ - { }; - m_handedNeedsApply = false; - } - - // This iterates through the various Logitech mice, if we have support. - #ifdef HAVE_LIBUSB - Q_FOREACH( LogitechMouse *logitechMouse, logitechMouseList ) { - logitechMouse->applyChanges(); - } - #endif -} - -void MouseSettings::save(KConfig *config) -{ - KConfigGroup group = config->group("Mouse"); - group.writeEntry("Acceleration",accelRate); - group.writeEntry("Threshold",thresholdMove); - if (handed == RIGHT_HANDED) - group.writeEntry("MouseButtonMapping",QString("RightHanded")); - else - group.writeEntry("MouseButtonMapping",QString("LeftHanded")); - group.writeEntry( "ReverseScrollPolarity", reverseScrollPolarity ); - - group = config->group("KDE"); - group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent|KConfig::Global); - group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent|KConfig::Global); - group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent|KConfig::Global); - group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent|KConfig::Global); - group.writeEntry("SingleClick", singleClick, KConfig::Persistent|KConfig::Global); - group.writeEntry("AutoSelectDelay", autoSelectDelay, KConfig::Persistent|KConfig::Global); - group.writeEntry("ChangeCursor", changeCursor,KConfig::Persistent|KConfig::Global); - // This iterates through the various Logitech mice, if we have support. -#ifdef HAVE_LIBUSB - Q_FOREACH( LogitechMouse *logitechMouse, logitechMouseList ) { - logitechMouse->save(config); - } -#endif - config->sync(); - KGlobalSettings::self()->emitChange(KGlobalSettings::MouseChanged); -} - void MouseConfig::slotScrollPolarityChanged() { settings->m_handedNeedsApply = true; diff --git a/kcontrol/input/mouse.desktop b/kcontrol/input/mouse.desktop index 67c2b7f9..11515cc5 100644 --- a/kcontrol/input/mouse.desktop +++ b/kcontrol/input/mouse.desktop @@ -2,12 +2,10 @@ Exec=kcmshell4 mouse Icon=preferences-desktop-mouse Type=Service -X-KDE-ServiceTypes=KCModule,KCModuleInit +X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/mouse/index.html X-KDE-Library=kcm_input -X-KDE-Init-Symbol=kcminit_mouse -X-KDE-Init-Phase=0 X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=input-devices @@ -201,7 +199,7 @@ X-KDE-Keywords[ca]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de X-KDE-Keywords[ca@valencia]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensitivitat de ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric X-KDE-Keywords[da]=Mus,Museacceleration,musetærskel,museknapper,markering,markørform,Input-enheder,knapkobling,klik,ikoner,feedback,Pointers,træk,dobbeltklik,enkeltklik,kobling,højrehåndet,venstrehåndet,pegeenhed,musehjul,museemulering,musenavigation,træk og slip,muserulning,scrolling,musefølsomhed,bevæg mus med numerisk tastatur,markører,cursor,rulning X-KDE-Keywords[de]=Maus,Mausbeschleunigung,Mausschwellwert,Maustasten,Auswahl,Cursor,Cursor-Form,Eingabegeräte,Knöpfe,Buttons,Zuordnungen,Klicks,Zeigegeräte,Doppelklick,Rechtshänder,Linkshänder,Ziehen,Mausrad,Maus-Emulation,Maus-Navigation,Ziehen und Ablegen mit der Maus,Blättern mit der Maus,Maus-Empfindlichkeit,Mauszeiger mit der Zahlentastatur verschieben,Maus-Emulation mit der Zahlentastatur -X-KDE-Keywords[el]=ποντίκι,επιτάχυνση ποντικιού,κατώφλι ποντικιού,κουμπιά ποντικιού,επιλογή,σχήμα δρομέα,συσκευές εισόδου,χαρτογράφηση κουμπιών,κλικ,εικονίδια,ανάδραση,δείκτες,έλξη,διπλό κλικ,μονό κλικ,χαρτογράφηση,δεξιόχειρας,αριστερόχειρας,συσκευή δείκτη,τροχός ποντικιού,εξομοίωση ποντικιού,πλοήγηση ποντικιού,έλξη και απόθεση ποντικιού,κύλιση ποντικιού,ευαισθησία ποντικιού,κίνηση ποντικιού με το αριθμητικό πληκτρολόγιο,εξομοίωση ποντικιού αριθμητικού πληκτρολογίου +X-KDE-Keywords[el]=πο��τίκι,επιτάχυνση ποντικιού,κατώφλι ποντικιού,κουμπιά ποντικιού,επιλογή,σχήμα δρομέα,συσκευές εισόδου,χαρτογράφηση κουμπιών,κλικ,εικονίδια,ανάδραση,δείκτες,έλξη,διπλό κλικ,μονό κλικ,χαρτογράφηση,δεξιόχειρας,αριστερόχειρας,συσκευή δείκτη,τροχός ποντικιού,εξομοίωση ποντικιού,πλοήγηση ποντικιού,έλξη και απόθεση ποντικιού,κύλιση ποντικιού,ευαισθησία ποντικιού,κίνηση ποντικιού με το αριθμητικό πληκτρολόγιο,εξομοίωση ποντικιού αριθμητικού πληκτρολογίου X-KDE-Keywords[en_GB]=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation X-KDE-Keywords[es]=Ratón,Aceleración de ratón,Umbral del ratón,Botones del ratón,Selección,Forma del cursor,Dispositivos de entrada,Mapeo de botones,Clic,iconos,reacción,Punteros,Arrastrar,Doble clic,clic sencillo,mapeo,diestro,zurdo,Dispositivo apuntador,Rueda del ratón,Emulación del ratón,Navegación con el ratón,Arrastrar y soltar con el ratón,Desplazamiento con el ratón,Sensibilidad del ratón,Mover el ratón con el teclado numérico,Emulación del ratón con el teclado numérico X-KDE-Keywords[et]=hiir,hiire kiirendamine,hiire lävi,hiirenupud,valik,kursori kuju,sisendseadmed,nuppude seostamine,klõps,klõpsamine,ikoonid,tagasiside,lohistamine,topeltklõps,ühekordne klõps,seostamine,paremakäelised,vasakukäelised,osutusseade,hiireratas,hiire emuleerimine,hiirega liikumine,hiirega lohistamine,hiirega kerimine,hiire tundlikkus,hiire liigutamine numbriklahvistikuga,hiire numbriklahvistiku emuleerimine diff --git a/kcontrol/input/mouse.h b/kcontrol/input/mouse.h index ebe55982..57d8c0b5 100644 --- a/kcontrol/input/mouse.h +++ b/kcontrol/input/mouse.h @@ -32,7 +32,7 @@ #define __MOUSECONFIG_H__ #include -#include +#include #include #include @@ -46,13 +46,11 @@ #ifdef HAVE_LIBUSB #include "logitechmouse.h" #endif +#include "mousesettings.h" #include #include "ui_kmousedlg.h" -#define RIGHT_HANDED 0 -#define LEFT_HANDED 1 - #include #include #include @@ -65,36 +63,6 @@ public: } }; - -class MouseSettings -{ -public: - void save(KConfig *); - void load(KConfig *); - void apply(bool force=false); -public: - int num_buttons; - int middle_button; - bool handedEnabled; - bool m_handedNeedsApply; - int handed; - double accelRate; - int thresholdMove; - int doubleClickInterval; - int dragStartTime; - int dragStartDist; - bool singleClick; - int autoSelectDelay; - bool changeCursor; - int wheelScrollLines; - bool reverseScrollPolarity; - - #ifdef HAVE_LIBUSB - // TODO: In Qt4, replace with a better container. - QList logitechMouseList; - #endif -}; - class MouseConfig : public KCModule { Q_OBJECT diff --git a/kcontrol/input/mousesettings.cpp b/kcontrol/input/mousesettings.cpp new file mode 100644 index 00000000..c635d049 --- /dev/null +++ b/kcontrol/input/mousesettings.cpp @@ -0,0 +1,244 @@ +/* + * mousesettings.cpp + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Layout management, enhancements: + * Copyright (c) 1999 Dirk A. Mueller + * + * SC/DC/AutoSelect/ChangeCursor: + * Copyright (c) 2000 David Faure + * + * Double click interval, drag time & dist + * Copyright (c) 2000 Bernd Gehrmann + * + * Large cursor support + * Visual activation TODO: speed + * Copyright (c) 2000 Rik Hemsley + * + * General/Advanced tabs + * Copyright (c) 2000 Brad Hughes + * + * redesign for KDE 2.2 + * Copyright (c) 2001 Ralf Nolden + * + * Logitech mouse support + * Copyright (C) 2004 Brad Hards + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "mousesettings.h" + +#include +#include + +#include +#include +#include + +void MouseSettings::load(KConfig *config) +{ + int accel_num = 0; + int accel_den = 0; + int threshold = 0; + double accel = 0.0; + XGetPointerControl( QX11Info::display(), + &accel_num, &accel_den, &threshold ); + accel = float(accel_num) / float(accel_den); + + // get settings from X server + int h = RIGHT_HANDED; + unsigned char map[20]; + num_buttons = XGetPointerMapping(QX11Info::display(), map, 20); + + handedEnabled = true; + + // ## keep this in sync with KGlobalSettings::mouseSettings + if( num_buttons == 1 ) + { + /* disable button remapping */ + handedEnabled = false; + } + else if( num_buttons == 2 ) + { + if ( (int)map[0] == 1 && (int)map[1] == 2 ) + h = RIGHT_HANDED; + else if ( (int)map[0] == 2 && (int)map[1] == 1 ) + h = LEFT_HANDED; + else + /* custom button setup: disable button remapping */ + handedEnabled = false; + } + else + { + middle_button = (int)map[1]; + if ( (int)map[0] == 1 && (int)map[2] == 3 ) + h = RIGHT_HANDED; + else if ( (int)map[0] == 3 && (int)map[2] == 1 ) + h = LEFT_HANDED; + else + { + /* custom button setup: disable button remapping */ + handedEnabled = false; + } + } + + KConfigGroup group = config->group("Mouse"); + double a = group.readEntry("Acceleration",-1.0); + if (a == -1) + accelRate = accel; + else + accelRate = a; + + int t = group.readEntry("Threshold",-1); + if (t == -1) + thresholdMove = threshold; + else + thresholdMove = t; + + QString key = group.readEntry("MouseButtonMapping"); + if (key == "RightHanded") + handed = RIGHT_HANDED; + else if (key == "LeftHanded") + handed = LEFT_HANDED; +#warning was key == NULL how was this working? is key.isNull() what the coder meant? + else if (key.isNull()) + handed = h; + reverseScrollPolarity = group.readEntry( "ReverseScrollPolarity", false); + m_handedNeedsApply = false; + + // SC/DC/AutoSelect/ChangeCursor + group = config->group("KDE"); + doubleClickInterval = group.readEntry("DoubleClickInterval", 400); + dragStartTime = group.readEntry("StartDragTime", 500); + dragStartDist = group.readEntry("StartDragDist", 4); + wheelScrollLines = group.readEntry("WheelScrollLines", 3); + + singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); + autoSelectDelay = group.readEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY); + changeCursor = group.readEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR); +} + +void MouseSettings::apply(bool force) +{ + XChangePointerControl( QX11Info::display(), + true, true, int(qRound(accelRate*10)), 10, thresholdMove); + + // 256 might seems extreme, but X has already been known to return 32, + // and we don't want to truncate things. Xlib limits the table to 256 bytes, + // so it's a good uper bound.. + unsigned char map[256]; + ::memset(map, 0, 256 * sizeof(unsigned char)); + num_buttons = XGetPointerMapping(QX11Info::display(), map, 256); + + int remap=(num_buttons>=1); + if (handedEnabled && (m_handedNeedsApply || force)) { + if( num_buttons == 1 ) + { + map[0] = (unsigned char) 1; + } + else if( num_buttons == 2 ) + { + if (handed == RIGHT_HANDED) + { + map[0] = (unsigned char) 1; + map[1] = (unsigned char) 3; + } + else + { + map[0] = (unsigned char) 3; + map[1] = (unsigned char) 1; + } + } + else // 3 buttons and more + { + if (handed == RIGHT_HANDED) + { + map[0] = (unsigned char) 1; + map[1] = (unsigned char) middle_button; + map[2] = (unsigned char) 3; + } + else + { + map[0] = (unsigned char) 3; + map[1] = (unsigned char) middle_button; + map[2] = (unsigned char) 1; + } + if( num_buttons >= 5 ) + { + // Apps seem to expect logical buttons 4,5 are the vertical wheel. + // With mice with more than 3 buttons (not including wheel) the physical + // buttons mapped to logical 4,5 may not be physical 4,5 , so keep + // this mapping, only possibly reversing them. + int pos; + for( pos = 0; pos < num_buttons; ++pos ) + if( map[pos] == 4 || map[pos] == 5 ) + break; + if( pos < num_buttons - 1 ) + { + map[pos] = reverseScrollPolarity ? (unsigned char) 5 : (unsigned char) 4; + map[pos+1] = reverseScrollPolarity ? (unsigned char) 4 : (unsigned char) 5; + } + } + } + int retval; + if (remap) + while ((retval=XSetPointerMapping(QX11Info::display(), map, + num_buttons)) == MappingBusy) + /* keep trying until the pointer is free */ + { }; + m_handedNeedsApply = false; + } + + // This iterates through the various Logitech mice, if we have support. +#ifdef HAVE_LIBUSB + Q_FOREACH( LogitechMouse *logitechMouse, logitechMouseList ) { + logitechMouse->applyChanges(); + } +#endif +} + +void MouseSettings::save(KConfig *config) +{ + KConfigGroup group = config->group("Mouse"); + group.writeEntry("Acceleration",accelRate); + group.writeEntry("Threshold",thresholdMove); + if (handed == RIGHT_HANDED) + group.writeEntry("MouseButtonMapping",QString("RightHanded")); + else + group.writeEntry("MouseButtonMapping",QString("LeftHanded")); + group.writeEntry( "ReverseScrollPolarity", reverseScrollPolarity ); + + group = config->group("KDE"); + group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent|KConfig::Global); + group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent|KConfig::Global); + group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent|KConfig::Global); + group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent|KConfig::Global); + group.writeEntry("SingleClick", singleClick, KConfig::Persistent|KConfig::Global); + group.writeEntry("AutoSelectDelay", autoSelectDelay, KConfig::Persistent|KConfig::Global); + group.writeEntry("ChangeCursor", changeCursor,KConfig::Persistent|KConfig::Global); + // This iterates through the various Logitech mice, if we have support. +#ifdef HAVE_LIBUSB + Q_FOREACH( LogitechMouse *logitechMouse, logitechMouseList ) { + logitechMouse->save(config); + } +#endif + config->sync(); + KGlobalSettings::self()->emitChange(KGlobalSettings::MouseChanged); +} diff --git a/kcontrol/input/mousesettings.h b/kcontrol/input/mousesettings.h new file mode 100644 index 00000000..72468de5 --- /dev/null +++ b/kcontrol/input/mousesettings.h @@ -0,0 +1,75 @@ +/* + * mousesettings.h + * + * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * + * Layout management, enhancements: + * Copyright (c) 1999 Dirk A. Mueller + * + * SC/DC/AutoSelect/ChangeCursor: + * Copyright (c) 2000 David Faure + * + * Requires the Qt widget libraries, available at no cost at + * http://www.troll.no/ + * + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + + +#ifndef __MOUSESETTINGS_H__ +#define __MOUSESETTINGS_H__ + +#include +#include + +#include +#include +#ifdef HAVE_LIBUSB +#include "logitechmouse.h" +#endif + +#define RIGHT_HANDED 0 +#define LEFT_HANDED 1 + +class MouseSettings +{ +public: + void save(KConfig *); + void load(KConfig *); + void apply(bool force=false); +public: + int num_buttons; + int middle_button; + bool handedEnabled; + bool m_handedNeedsApply; + int handed; + double accelRate; + int thresholdMove; + int doubleClickInterval; + int dragStartTime; + int dragStartDist; + bool singleClick; + int autoSelectDelay; + bool changeCursor; + int wheelScrollLines; + bool reverseScrollPolarity; + +#ifdef HAVE_LIBUSB + QList logitechMouseList; +#endif +}; + +#endif + diff --git a/kcontrol/keyboard/CMakeLists.txt b/kcontrol/keyboard/CMakeLists.txt index 52f08b8c..61f74096 100644 --- a/kcontrol/keyboard/CMakeLists.txt +++ b/kcontrol/keyboard/CMakeLists.txt @@ -29,3 +29,22 @@ install( FILES keyboard_new.desktop DESTINATION ${KDE4_DATA_INSTALL_DIR}/solid/actions ) + +########### next target ############### + +add_executable(kkeyboard kkeyboard.cpp) +target_link_libraries(kkeyboard + KDE4::kdeui + ${X11_LIBRARIES} + ${X11_Xkbfile_LIB} +) + +install( + TARGETS kkeyboard + DESTINATION ${KDE4_BIN_INSTALL_DIR} +) + +install( + FILES kkeyboard.desktop + DESTINATION ${KDE4_AUTOSTART_INSTALL_DIR} +) diff --git a/kcontrol/keyboard/kcm_keyboard.desktop b/kcontrol/keyboard/kcm_keyboard.desktop index 02624ab1..a708558f 100644 --- a/kcontrol/keyboard/kcm_keyboard.desktop +++ b/kcontrol/keyboard/kcm_keyboard.desktop @@ -2,13 +2,11 @@ Exec=kcmshell4 kcm_keyboard Icon=preferences-desktop-keyboard Type=Service -X-KDE-ServiceTypes=KCModule,KCModuleInit +X-KDE-ServiceTypes=KCModule X-DocPath=kcontrol/keyboard/index.html Categories=Qt;KDE;X-KDE-settings-hardware; X-KDE-Library=kcm_keyboard -X-KDE-Init-Symbol=kcminit_keyboard -X-KDE-Init-Phase=0 X-KDE-ParentApp=kcontrol X-KDE-System-Settings-Parent-Category=input-devices diff --git a/kcontrol/keyboard/keyboardconfig.cpp b/kcontrol/keyboard/keyboardconfig.cpp index 15e254c7..d2711e25 100644 --- a/kcontrol/keyboard/keyboardconfig.cpp +++ b/kcontrol/keyboard/keyboardconfig.cpp @@ -19,11 +19,9 @@ #include "keyboardconfig.h" #include "keyboardlayoutdialog.h" #include "keyboardoptionsdialog.h" +#include "keyboardconfig_common.h" #include -#include -#include -#include #include #include #include @@ -33,41 +31,6 @@ #include #include -#include -#include - -static const float s_defaultrepeatdelay = 660.0; -static const float s_defaultrepeatrate = 25.0; - -static QList kLayoutsFromConfig() -{ - KConfig kconfig("kcminputrc", KConfig::NoGlobals); - KConfigGroup kconfiggroup(&kconfig, "Keyboard"); - const KKeyboardType defaultlayout = KKeyboardLayout::defaultLayout(); - const QByteArray layoutsmodel = kconfiggroup.readEntry("LayoutsModel", defaultlayout.model); - const QByteArray layoutsoptions = kconfiggroup.readEntry("LayoutsOptions", defaultlayout.option); - const QStringList layoutslayouts = kconfiggroup.readEntry( - "LayoutsLayouts", - QStringList() << QString::fromLatin1(defaultlayout.layout.constData(), defaultlayout.layout.size()) - ); - const QStringList layoutsvariants = kconfiggroup.readEntry( - "LayoutsVariants", - QStringList() << QString::fromLatin1(defaultlayout.variant.constData(), defaultlayout.variant.size()) - ); - QList result; - for (int i = 0; i < layoutslayouts.size(); i++) { - KKeyboardType kkeyboardtype; - kkeyboardtype.model = layoutsmodel; - kkeyboardtype.layout = layoutslayouts.at(i).toLatin1(); - if (i < layoutsvariants.size()) { - kkeyboardtype.variant = layoutsvariants.at(i).toLatin1(); - } - kkeyboardtype.option = layoutsoptions; - result.append(kkeyboardtype); - } - return result; -} - static void kFillTreeFromLayouts(QTreeWidget *treewidget, const QList &layouts) { treewidget->clear(); @@ -104,46 +67,6 @@ static QList kGetLayoutsFromTree(QTreeWidget *treewidget, const Q return result; } -static void kApplyKeyboardConfig() -{ - const QList layouts = kLayoutsFromConfig(); - if (layouts.size() > 0) { - KKeyboardLayout().setLayouts(layouts); - } - - KConfig kconfig("kcminputrc", KConfig::NoGlobals); - KConfigGroup kconfiggroup(&kconfig, "Keyboard"); - const float repeatdelay = kconfiggroup.readEntry("RepeatDelay", s_defaultrepeatdelay); - const float repeatrate = kconfiggroup.readEntry("RepeatRate", s_defaultrepeatrate); - - XkbDescPtr xkbkeyboard = XkbAllocKeyboard(); - if (!xkbkeyboard) { - kError() << "Failed to allocate keyboard"; - return; - } - Status xkbgetresult = XkbGetControls(QX11Info::display(), XkbRepeatKeysMask, xkbkeyboard); - if (xkbgetresult != Success) { - kError() << "Failed to get keyboard repeat controls"; - XkbFreeKeyboard(xkbkeyboard, 0, true); - return; - } - xkbkeyboard->ctrls->repeat_delay = repeatdelay; - xkbkeyboard->ctrls->repeat_interval = qFloor(1000 / repeatrate + 0.5); - const Bool xkbsetresult = XkbSetControls(QX11Info::display(), XkbRepeatKeysMask, xkbkeyboard); - if (xkbsetresult != True) { - kError() << "Failed to set keyboard repeat controls"; - } - XkbFreeKeyboard(xkbkeyboard, 0, true); -} - -extern "C" -{ - Q_DECL_EXPORT void kcminit_keyboard() - { - kApplyKeyboardConfig(); - } -} - K_PLUGIN_FACTORY(KCMKeyboardFactory, registerPlugin();) K_EXPORT_PLUGIN(KCMKeyboardFactory("kcmkeyboard", "kcm_keyboard")) diff --git a/kcontrol/keyboard/keyboardconfig_common.h b/kcontrol/keyboard/keyboardconfig_common.h new file mode 100644 index 00000000..999276a2 --- /dev/null +++ b/kcontrol/keyboard/keyboardconfig_common.h @@ -0,0 +1,97 @@ +/* This file is part of the KDE project + Copyright (C) 2023 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KEYBOARDCONFIG_COMMON_H +#define KEYBOARDCONFIG_COMMON_H + +#include +#include +#include +#include +#include +#include + +#include +#include + +static const float s_defaultrepeatdelay = 660.0; +static const float s_defaultrepeatrate = 25.0; + +static QList kLayoutsFromConfig() +{ + KConfig kconfig("kcminputrc", KConfig::NoGlobals); + KConfigGroup kconfiggroup(&kconfig, "Keyboard"); + const KKeyboardType defaultlayout = KKeyboardLayout::defaultLayout(); + const QByteArray layoutsmodel = kconfiggroup.readEntry("LayoutsModel", defaultlayout.model); + const QByteArray layoutsoptions = kconfiggroup.readEntry("LayoutsOptions", defaultlayout.option); + const QStringList layoutslayouts = kconfiggroup.readEntry( + "LayoutsLayouts", + QStringList() << QString::fromLatin1(defaultlayout.layout.constData(), defaultlayout.layout.size()) + ); + const QStringList layoutsvariants = kconfiggroup.readEntry( + "LayoutsVariants", + QStringList() << QString::fromLatin1(defaultlayout.variant.constData(), defaultlayout.variant.size()) + ); + QList result; + for (int i = 0; i < layoutslayouts.size(); i++) { + KKeyboardType kkeyboardtype; + kkeyboardtype.model = layoutsmodel; + kkeyboardtype.layout = layoutslayouts.at(i).toLatin1(); + if (i < layoutsvariants.size()) { + kkeyboardtype.variant = layoutsvariants.at(i).toLatin1(); + } + kkeyboardtype.option = layoutsoptions; + result.append(kkeyboardtype); + } + return result; +} + +static void kApplyKeyboardConfig() +{ + const QList layouts = kLayoutsFromConfig(); + if (layouts.size() > 0) { + KKeyboardLayout().setLayouts(layouts); + } + + KConfig kconfig("kcminputrc", KConfig::NoGlobals); + KConfigGroup kconfiggroup(&kconfig, "Keyboard"); + const float repeatdelay = kconfiggroup.readEntry("RepeatDelay", s_defaultrepeatdelay); + const float repeatrate = kconfiggroup.readEntry("RepeatRate", s_defaultrepeatrate); + + XkbDescPtr xkbkeyboard = XkbAllocKeyboard(); + if (!xkbkeyboard) { + kError() << "Failed to allocate keyboard"; + return; + } + Status xkbgetresult = XkbGetControls(QX11Info::display(), XkbRepeatKeysMask, xkbkeyboard); + if (xkbgetresult != Success) { + kError() << "Failed to get keyboard repeat controls"; + XkbFreeKeyboard(xkbkeyboard, 0, true); + return; + } + xkbkeyboard->ctrls->repeat_delay = repeatdelay; + xkbkeyboard->ctrls->repeat_interval = qFloor(1000 / repeatrate + 0.5); + const Bool xkbsetresult = XkbSetControls(QX11Info::display(), XkbRepeatKeysMask, xkbkeyboard); + if (xkbsetresult != True) { + kError() << "Failed to set keyboard repeat controls"; + } + XkbFreeKeyboard(xkbkeyboard, 0, true); +} + + +#endif // KEYBOARDCONFIG_COMMON_H diff --git a/kcontrol/keyboard/kkeyboard.cpp b/kcontrol/keyboard/kkeyboard.cpp new file mode 100644 index 00000000..58e4fc7a --- /dev/null +++ b/kcontrol/keyboard/kkeyboard.cpp @@ -0,0 +1,31 @@ +/* This file is part of the KDE project + Copyright (C) 2024 Ivailo Monev + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2, as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include + +#include "keyboardconfig_common.h" + +int main(int argc, char *argv[]) +{ + // application instance for events processing + QCoreApplication app(argc, argv); + + kApplyKeyboardConfig(); + return 0; +} diff --git a/kcontrol/keyboard/kkeyboard.desktop b/kcontrol/keyboard/kkeyboard.desktop new file mode 100644 index 00000000..09c5f50e --- /dev/null +++ b/kcontrol/keyboard/kkeyboard.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Type=Service +Name=KDE Keyboard +Exec=kkeyboard +Icon=preferences-desktop-keyboard +StartupNotify=false +OnlyShowIn=KDE; +X-KDE-autostart-phase=0 +X-DocPath=kcontrol/keyboard/index.html diff --git a/plasma/shells/plasma-desktop/plasmaapp.cpp b/plasma/shells/plasma-desktop/plasmaapp.cpp index 89fc6059..bf2d1690 100644 --- a/plasma/shells/plasma-desktop/plasmaapp.cpp +++ b/plasma/shells/plasma-desktop/plasmaapp.cpp @@ -114,7 +114,6 @@ PlasmaApp::PlasmaApp() m_panelHidden(0), m_phase(0), m_klauncher(nullptr), - m_kcminit(nullptr), m_wmproc(nullptr), m_startupsuspend(0), m_dialogActive(false), @@ -181,13 +180,6 @@ PlasmaApp::PlasmaApp() QDBusConnection::sessionBus(), this ); - m_kcminit = new QDBusInterface( - QLatin1String("org.kde.kcminit"), - QLatin1String("/kcminit"), - QLatin1String("org.kde.KCMInit"), - QDBusConnection::sessionBus(), - this - ); const bool failsafe = (qgetenv("KDE_FAILSAFE").toInt() == 1); if (!failsafe) { m_sessionManager = true; @@ -1174,13 +1166,11 @@ void PlasmaApp::nextPhase() sessionInterface->startService(kdedInterface); } m_klauncher->asyncCall("autoStart", int(0)); - m_kcminit->asyncCall("runPhase1"); QTimer::singleShot(s_phasedelay, this, SLOT(nextPhase())); break; } case 1: { m_klauncher->asyncCall("autoStart", int(1)); - m_kcminit->asyncCall("runPhase2"); QTimer::singleShot(s_phasedelay, this, SLOT(nextPhase())); break; } diff --git a/plasma/shells/plasma-desktop/plasmaapp.h b/plasma/shells/plasma-desktop/plasmaapp.h index f1b168bb..2617e14b 100644 --- a/plasma/shells/plasma-desktop/plasmaapp.h +++ b/plasma/shells/plasma-desktop/plasmaapp.h @@ -164,7 +164,6 @@ private: QHash > m_widgetExplorers; int m_phase; QDBusInterface* m_klauncher; - QDBusInterface* m_kcminit; QProcess* m_wmproc; int m_startupsuspend; bool m_dialogActive; diff --git a/startkde.cmake b/startkde.cmake index 012ef12e..c50ca5e2 100644 --- a/startkde.cmake +++ b/startkde.cmake @@ -116,16 +116,6 @@ dbus-update-activation-environment DISPLAY XAUTHORITY XDG_CURRENT_DESKTOP \ # update it when that happens kbuildsycoca4 -# Start kcminit_startup -kcminit_startup -kcminit_result=$? -if test $? -ne 0; then - # Startup error - echo "startkde: Could not start kcminit_startup ($kcminit_result). Check your installation." 1>&2 - xmessage -geometry 500x100 "Could not start kcminit_startup ($kcminit_result). Check your installation." - exit 1 -fi - # finally, give the session control to plasma-desktop plasma-desktop plasma_result=$?