mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-23 18:32:50 +00:00
331 lines
10 KiB
C++
331 lines
10 KiB
C++
/* Copyright (C) 2008 Michael Jansen <kde@michael-jansen.biz>
|
|
|
|
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.
|
|
*/
|
|
|
|
#include "globalshortcutsregistry.h"
|
|
#include "component.h"
|
|
#include "globalshortcut.h"
|
|
#include "globalshortcutcontext.h"
|
|
|
|
#include "kdebug.h"
|
|
#include "kglobal.h"
|
|
#include "klocale.h"
|
|
#include "knotification.h"
|
|
|
|
#include <QKeySequence>
|
|
#include <QDBusConnection>
|
|
|
|
#ifdef Q_WS_X11
|
|
#include "kglobalaccel_x11.h"
|
|
#include <QtGui/qx11info_x11.h>
|
|
#include <QApplication>
|
|
#else
|
|
#include "kglobalaccel_qws.h"
|
|
#endif
|
|
|
|
GlobalShortcutsRegistry::GlobalShortcutsRegistry()
|
|
: QObject(),
|
|
_active_keys(),
|
|
_components(),
|
|
_manager(new KGlobalAccelImpl(this)),
|
|
_config("kglobalshortcutsrc", KConfig::SimpleConfig)
|
|
{
|
|
_manager->setEnabled(true);
|
|
}
|
|
|
|
|
|
GlobalShortcutsRegistry::~GlobalShortcutsRegistry()
|
|
{
|
|
_manager->setEnabled(false);
|
|
|
|
// Ungrab all keys. We don't go over GlobalShortcuts because
|
|
// GlobalShortcutsRegistry::self() doesn't work anymore.
|
|
Q_FOREACH (const int key, _active_keys.keys()) {
|
|
_manager->grabKey(key, false);
|
|
}
|
|
_active_keys.clear();
|
|
}
|
|
|
|
KdeDGlobalAccel::Component *GlobalShortcutsRegistry::addComponent(KdeDGlobalAccel::Component *component)
|
|
{
|
|
if (_components.value(component->uniqueName())) {
|
|
Q_ASSERT_X(false, "GlobalShortcutsRegistry::addComponent", "component already registered?!?!");
|
|
return _components.value(component->uniqueName());
|
|
}
|
|
|
|
_components.insert(component->uniqueName(), component);
|
|
QDBusConnection conn(QDBusConnection::sessionBus());
|
|
|
|
conn.registerObject(component->dbusPath().path(), component, QDBusConnection::ExportScriptableContents);
|
|
return component;
|
|
}
|
|
|
|
|
|
void GlobalShortcutsRegistry::activateShortcuts()
|
|
{
|
|
Q_FOREACH (KdeDGlobalAccel::Component *component, _components) {
|
|
component->activateShortcuts();
|
|
}
|
|
}
|
|
|
|
QList<KdeDGlobalAccel::Component*> GlobalShortcutsRegistry::allMainComponents() const
|
|
{
|
|
return _components.values();
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::clear()
|
|
{
|
|
Q_FOREACH(KdeDGlobalAccel::Component *component, _components) {
|
|
delete component;
|
|
}
|
|
_components.clear();
|
|
|
|
// The shortcuts should have deregistered themselves
|
|
Q_ASSERT(_active_keys.isEmpty());
|
|
}
|
|
|
|
QDBusObjectPath GlobalShortcutsRegistry::dbusPath() const
|
|
{
|
|
return _dbusPath;
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::deactivateShortcuts(bool temporarily)
|
|
{
|
|
Q_FOREACH (KdeDGlobalAccel::Component *component, _components) {
|
|
component->deactivateShortcuts(temporarily);
|
|
}
|
|
}
|
|
|
|
GlobalShortcut *GlobalShortcutsRegistry::getActiveShortcutByKey(int key) const
|
|
{
|
|
return _active_keys.value(key);
|
|
}
|
|
|
|
KdeDGlobalAccel::Component *GlobalShortcutsRegistry::getComponent(const QString &uniqueName)
|
|
{
|
|
return _components.value(uniqueName);
|
|
}
|
|
|
|
GlobalShortcut *GlobalShortcutsRegistry::getShortcutByKey(int key) const
|
|
{
|
|
Q_FOREACH (KdeDGlobalAccel::Component *component, _components) {
|
|
GlobalShortcut *rc = component->getShortcutByKey(key);
|
|
if (rc) {
|
|
return rc;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
QList<GlobalShortcut*> GlobalShortcutsRegistry::getShortcutsByKey(int key) const
|
|
{
|
|
QList<GlobalShortcut *> rc;
|
|
|
|
Q_FOREACH (KdeDGlobalAccel::Component *component, _components) {
|
|
rc = component->getShortcutsByKey(key);
|
|
if (!rc.isEmpty()) {
|
|
return rc;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
bool GlobalShortcutsRegistry::isShortcutAvailable(int shortcut, const QString &componentName, const QString &contextName) const
|
|
{
|
|
Q_FOREACH (KdeDGlobalAccel::Component *component, _components) {
|
|
if (!component->isShortcutAvailable(shortcut, componentName, contextName)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
GlobalShortcutsRegistry * GlobalShortcutsRegistry::self()
|
|
{
|
|
K_GLOBAL_STATIC(GlobalShortcutsRegistry, self);
|
|
return self;
|
|
}
|
|
|
|
bool GlobalShortcutsRegistry::keyPressed(int keyQt)
|
|
{
|
|
GlobalShortcut *shortcut = getShortcutByKey(keyQt);
|
|
if (!shortcut) {
|
|
// This can happen for example with the ALT-Print shortcut of kwin.
|
|
// ALT+PRINT is SYSREQ on my keyboard. So we grab something we think
|
|
// is ALT+PRINT but symXToKeyQt and modXToQt make ALT+SYSREQ of it
|
|
// when pressed (correctly). We can't match that.
|
|
kDebug() << "Got unknown key" << QKeySequence(keyQt).toString();
|
|
|
|
// In production mode just do nothing.
|
|
return false;
|
|
} else if (!shortcut->isActive()) {
|
|
kDebug() << "Got inactive key" << QKeySequence(keyQt).toString();
|
|
|
|
// In production mode just do nothing.
|
|
return false;
|
|
}
|
|
|
|
kDebug() << QKeySequence(keyQt).toString() << "=" << shortcut->uniqueName();
|
|
|
|
QStringList data(shortcut->context()->component()->uniqueName());
|
|
data.append(shortcut->uniqueName());
|
|
data.append(shortcut->context()->component()->friendlyName());
|
|
data.append(shortcut->friendlyName());
|
|
#ifdef Q_WS_X11
|
|
// Make sure kglobalacceld has ungrabbed the keyboard after receiving the
|
|
// keypress, otherwise actions in application that try to grab the
|
|
// keyboard (e.g. in kwin) may fail to do so. There is still a small race
|
|
// condition with this being out-of-process.
|
|
qApp->syncX();
|
|
#endif
|
|
|
|
// 1st Invoke the action
|
|
shortcut->context()->component()->emitGlobalShortcutPressed( *shortcut );
|
|
|
|
// Then do anything else
|
|
KNotification *notification = new KNotification("globalshortcutpressed", KNotification::CloseOnTimeout);
|
|
notification->setText(i18n("The global shortcut for %1 was issued.", shortcut->friendlyName()));
|
|
notification->addContext( "application", shortcut->context()->component()->friendlyName() );
|
|
notification->sendEvent();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void GlobalShortcutsRegistry::loadSettings()
|
|
{
|
|
Q_FOREACH (const QString &groupName, _config.groupList()) {
|
|
kDebug() << "Loading group " << groupName;
|
|
|
|
Q_ASSERT(groupName.indexOf('\x1d')==-1);
|
|
|
|
// loadSettings isn't designed to be called in between. Only at the
|
|
// beginning.
|
|
Q_ASSERT(!getComponent(groupName));
|
|
|
|
KConfigGroup configGroup(&_config, groupName);
|
|
|
|
// We previously stored the friendly name in a separate group. migrate
|
|
// that
|
|
QString friendlyName;
|
|
KConfigGroup friendlyGroup(&configGroup, "Friendly Name");
|
|
if (friendlyGroup.isValid()) {
|
|
friendlyName = friendlyGroup.readEntry("Friendly Name");
|
|
friendlyGroup.deleteGroup();
|
|
} else {
|
|
friendlyName = configGroup.readEntry("_k_friendly_name");
|
|
}
|
|
|
|
// Create the component
|
|
KdeDGlobalAccel::Component *component = new KdeDGlobalAccel::Component(groupName, friendlyName, this);
|
|
|
|
// Now load the contexts
|
|
Q_FOREACH(const QString& context, configGroup.groupList()) {
|
|
// Skip the friendly name group
|
|
if (context == "Friendly Name") {
|
|
continue;
|
|
}
|
|
|
|
KConfigGroup contextGroup(&configGroup, context);
|
|
QString contextFriendlyName = contextGroup.readEntry("_k_friendly_name");
|
|
component->createGlobalShortcutContext(context, contextFriendlyName);
|
|
component->activateGlobalShortcutContext(context);
|
|
component->loadSettings(contextGroup);
|
|
}
|
|
|
|
// Load the default context
|
|
component->activateGlobalShortcutContext("default");
|
|
component->loadSettings(configGroup);
|
|
}
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::grabKeys()
|
|
{
|
|
activateShortcuts();
|
|
}
|
|
|
|
bool GlobalShortcutsRegistry::registerKey(int key, GlobalShortcut *shortcut)
|
|
{
|
|
if (key == 0) {
|
|
kDebug() << shortcut->uniqueName() << ": Key '" << QKeySequence(key).toString()
|
|
<< "' already taken by " << _active_keys.value(key)->uniqueName() << ".";
|
|
return false;
|
|
} else if (_active_keys.value(key)) {
|
|
kDebug() << shortcut->uniqueName() << ": Attempt to register key 0.";
|
|
return false;
|
|
}
|
|
|
|
kDebug() << "Registering key" << QKeySequence(key).toString() << "for"
|
|
<< shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName();
|
|
|
|
_active_keys.insert(key, shortcut);
|
|
return _manager->grabKey(key, true);
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::setAccelManager(KGlobalAccelImpl *manager)
|
|
{
|
|
_manager = manager;
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::setDBusPath(const QDBusObjectPath &path)
|
|
{
|
|
_dbusPath = path;
|
|
}
|
|
|
|
KdeDGlobalAccel::Component *GlobalShortcutsRegistry::takeComponent(KdeDGlobalAccel::Component *component)
|
|
{
|
|
QDBusConnection conn(QDBusConnection::sessionBus());
|
|
conn.unregisterObject(component->dbusPath().path());
|
|
return _components.take(component->uniqueName());
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::ungrabKeys()
|
|
{
|
|
deactivateShortcuts();
|
|
}
|
|
|
|
bool GlobalShortcutsRegistry::unregisterKey(int key, GlobalShortcut *shortcut)
|
|
{
|
|
if (_active_keys.value(key) != shortcut) {
|
|
// The shortcut doesn't own the key or the key isn't grabbed
|
|
return false;
|
|
}
|
|
|
|
kDebug() << "Unregistering key" << QKeySequence(key).toString() << "for"
|
|
<< shortcut->context()->component()->uniqueName() << ":" << shortcut->uniqueName();
|
|
|
|
_manager->grabKey(key, false);
|
|
_active_keys.take(key);
|
|
return true;
|
|
}
|
|
|
|
void GlobalShortcutsRegistry::writeSettings() const
|
|
{
|
|
Q_FOREACH(const KdeDGlobalAccel::Component *component, GlobalShortcutsRegistry::self()->allMainComponents()) {
|
|
KConfigGroup configGroup(&_config, component->uniqueName());
|
|
if (component->allShortcuts().isEmpty()) {
|
|
configGroup.deleteGroup();
|
|
delete component;
|
|
} else {
|
|
component->writeSettings(configGroup);
|
|
}
|
|
}
|
|
|
|
_config.sync();
|
|
}
|
|
|
|
#include "moc_globalshortcutsregistry.cpp"
|