* Copyright (C) 2010 Andriy Rysin (rysin@kde.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "layout_memory.h"
#include "debug.h"
#include <QX11Info>
#include <kwindowsystem.h>
#include "x11_helper.h"
#include "xkb_helper.h"
LayoutMemory::LayoutMemory(const KeyboardConfig& keyboardConfig_):
prevLayoutList(X11Helper::getLayoutsList()),
keyboardConfig(keyboardConfig_)
{
registerListeners();
}
LayoutMemory::~LayoutMemory()
{
unregisterListeners();
}
void LayoutMemory::configChanged()
{
unregisterListeners();
registerListeners();
}
void LayoutMemory::registerListeners()
{
if( keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_WINDOW
|| keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_APPLICATION ) {
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &LayoutMemory::windowChanged);
}
if( keyboardConfig.switchingPolicy == KeyboardConfig::SWITCH_POLICY_DESKTOP ) {
connect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &LayoutMemory::desktopChanged);
}
}
void LayoutMemory::unregisterListeners()
{
disconnect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &LayoutMemory::windowChanged);
disconnect(KWindowSystem::self(), &KWindowSystem::currentDesktopChanged, this, &LayoutMemory::desktopChanged);
}
QString LayoutMemory::getCurrentMapKey() {
switch(keyboardConfig.switchingPolicy) {
case KeyboardConfig::SWITCH_POLICY_WINDOW: {
WId wid = KWindowSystem::self()->activeWindow();
KWindowInfo winInfo(wid, NET::WMWindowType);
NET::WindowType windowType = winInfo.windowType( NET::NormalMask | NET::DesktopMask | NET::DialogMask );
qCDebug(KCM_KEYBOARD, ) << "window type" << windowType;
if( windowType == NET::Desktop )
return previousLayoutMapKey;
if( windowType != NET::Unknown && windowType != NET::Normal && windowType != NET::Dialog )
return QString();
return QString::number(wid);
}
case KeyboardConfig::SWITCH_POLICY_APPLICATION: {
WId wid = KWindowSystem::self()->activeWindow();
KWindowInfo winInfo(wid, NET::WMWindowType, NET::WM2WindowClass);
NET::WindowType windowType = winInfo.windowType( NET::NormalMask | NET::DesktopMask | NET::DialogMask );
qCDebug(KCM_KEYBOARD, ) << "window type" << windowType;
if( windowType == NET::Desktop )
return previousLayoutMapKey;
if( windowType != NET::Unknown && windowType != NET::Normal && windowType != NET::Dialog )
return QString();
qCDebug(KCM_KEYBOARD, ) << "New active window with class.class: " << winInfo.windowClassClass();
return QString(winInfo.windowClassClass());
}
case KeyboardConfig::SWITCH_POLICY_DESKTOP:
return QString::number(KWindowSystem::self()->currentDesktop());
default:
return QString();
}
}
static
bool isExtraSubset(const QList<LayoutUnit>& allLayouts, const QList<LayoutUnit>& newList)
{
if( allLayouts.first() != newList.first() )
return false;
foreach(const LayoutUnit& layoutUnit, newList) {
if( ! allLayouts.contains(layoutUnit) )
return false;
}
return true;
}
void LayoutMemory::layoutMapChanged()
{
QList<LayoutUnit> newLayoutList(X11Helper::getLayoutsList());
if( prevLayoutList == newLayoutList )
return;
qCDebug(KCM_KEYBOARD, ) << "Layout map change: " << LayoutSet::toString(prevLayoutList) << "-->" << LayoutSet::toString(newLayoutList);
prevLayoutList = newLayoutList;
if( keyboardConfig.configureLayouts
&& isExtraSubset(keyboardConfig.layouts, newLayoutList) ) {
qCDebug(KCM_KEYBOARD, ) << "Layout map change for extra layout";
layoutChanged();
}
else {
if (newLayoutList != keyboardConfig.getDefaultLayouts()) {
qCDebug(KCM_KEYBOARD, ) << "Layout map change from external source: clearing layout memory";
layoutMap.clear();
}
}
}
void LayoutMemory::layoutChanged()
{
QString layoutMapKey = getCurrentMapKey();
if( layoutMapKey.isEmpty() )
return;
layoutMap[ layoutMapKey ] = X11Helper::getCurrentLayouts();
}
void LayoutMemory::setCurrentLayoutFromMap()
{
QString layoutMapKey = getCurrentMapKey();
if( layoutMapKey.isEmpty() )
return;
if( ! layoutMap.contains(layoutMapKey) ) {
if( ! X11Helper::isDefaultLayout() ) {
if( keyboardConfig.configureLayouts && X11Helper::getLayoutsList() != keyboardConfig.getDefaultLayouts() ) {
XkbHelper::initializeKeyboardLayouts(keyboardConfig.getDefaultLayouts());
}
X11Helper::setDefaultLayout();
}
}
else {
LayoutSet layoutFromMap = layoutMap[layoutMapKey];
qCDebug(KCM_KEYBOARD, ) << "Setting layout map item" << layoutFromMap.currentLayout.toString()
<< "for container key" << layoutMapKey;
LayoutSet currentLayouts = X11Helper::getCurrentLayouts();
if( layoutFromMap.layouts != currentLayouts.layouts ) {
if( keyboardConfig.configureLayouts ) {
XkbHelper::initializeKeyboardLayouts(layoutFromMap.layouts);
}
X11Helper::setLayout( layoutFromMap.currentLayout );
}
else if( layoutFromMap.currentLayout != currentLayouts.currentLayout ) {
X11Helper::setLayout( layoutFromMap.currentLayout );
}
}
previousLayoutMapKey = layoutMapKey;
}
void LayoutMemory::windowChanged(WId )
{
setCurrentLayoutFromMap();
}
void LayoutMemory::desktopChanged(int )
{
setCurrentLayoutFromMap();
}