2 * Copyright (C) 2006 Andriy Rysin (rysin@kde.org)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include <ksharedconfig.h>
26 #include <kconfiggroup.h>
29 #include "kxkbconfig.h"
30 #include "x11helper.h"
33 static const char* switchModes
[SWITCH_POLICY_COUNT
] = {
34 "Global", "Desktop", "WinClass", "Window"
37 const LayoutUnit DEFAULT_LAYOUT_UNIT
= LayoutUnit("us", "");
38 const char* DEFAULT_MODEL
= "pc104";
40 const char* KxkbConfig::OPTIONS_SEPARATOR
= ",";
42 KxkbConfig::KxkbConfig() {
43 m_layouts
.append( DEFAULT_LAYOUT_UNIT
);
46 int KxkbConfig::getDefaultLayout()
48 if( m_layouts
.size() == 0 )
49 return 0; //DEFAULT_LAYOUT_UNIT;
51 return 0; //m_layouts[0];
54 bool KxkbConfig::load(int loadMode
)
56 // kDebug() << "Reading configuration";
57 KConfigGroup
config(KSharedConfig::openConfig( "kxkbrc", KConfig::NoGlobals
), "Layout");
59 // m_enableXkbOptions = config.readEntry("EnableXkbOptions", false);
61 m_useKxkb
= config
.readEntry("Use", false);
62 kDebug() << "Use kxkb" << m_useKxkb
;
64 if( m_useKxkb
== false && loadMode
== LOAD_ACTIVE_OPTIONS
)
67 m_indicatorOnly
= config
.readEntry("IndicatorOnly", false);
68 kDebug() << "Indicator only" << m_indicatorOnly
;
70 m_showSingle
= config
.readEntry("ShowSingle", false);
71 m_showFlag
= config
.readEntry("ShowFlag", true);
73 m_model
= config
.readEntry("Model", DEFAULT_MODEL
);
74 kDebug() << "Model:" << m_model
;
76 QStringList layoutList
;
77 layoutList
= config
.readEntry("LayoutList", layoutList
);
79 if( layoutList
.count() == 0 )
80 layoutList
.append("us");
83 for(QStringList::ConstIterator it
= layoutList
.constBegin(); it
!= layoutList
.constEnd() ; ++it
) {
84 LayoutUnit
layoutUnit(*it
);
85 m_layouts
.append( layoutUnit
);
86 kDebug() << " added layout" << layoutUnit
.toPair();
89 // kDebug() << "Found " << m_layouts.count() << " layouts, default is " << m_layouts[getDefaultLayout()].toPair();
91 QStringList displayNamesList
;
92 displayNamesList
= config
.readEntry("DisplayNames", displayNamesList
);
94 for(QStringList::ConstIterator it
= displayNamesList
.constBegin(); it
!= displayNamesList
.constEnd() ; ++it
) {
95 if( i
< m_layouts
.count() ) {
96 m_layouts
[i
].setDisplayName(*it
);
101 QString layoutOwner
= config
.readEntry("SwitchMode", "Global");
103 if( layoutOwner
== "WinClass" ) {
104 m_switchingPolicy
= SWITCH_POLICY_WIN_CLASS
;
106 else if( layoutOwner
== "Window" ) {
107 m_switchingPolicy
= SWITCH_POLICY_WINDOW
;
109 else if( layoutOwner
== "Desktop" ) {
110 m_switchingPolicy
= SWITCH_POLICY_DESKTOP
;
112 else /*if( layoutOwner == "Global" )*/ {
113 m_switchingPolicy
= SWITCH_POLICY_GLOBAL
;
116 // if( m_layouts.count() < 2 && m_switchingPolicy != SWITCH_POLICY_GLOBAL ) {
117 // kWarning() << "Layout count is less than 2, using Global switching policy" ;
118 // m_switchingPolicy = SWITCH_POLICY_GLOBAL;
121 kDebug() << "Layout owner mode" << layoutOwner
;
123 #ifdef STICKY_SWITCHING
124 m_stickySwitching
= config
.readEntry("StickySwitching", false);
125 m_stickySwitchingDepth
= config
.readEntry("StickySwitchingDepth", "2").toInt();
126 if( m_stickySwitchingDepth
< 2 )
127 m_stickySwitchingDepth
= 2;
129 if( m_stickySwitching
== true ) {
130 if( m_layouts
.count() < 3 ) {
131 kWarning() << "Layout count is less than 3, sticky switching will be off" ;
132 m_stickySwitching
= false;
135 if( (int)m_layouts
.count() - 1 < m_stickySwitchingDepth
) {
136 kWarning() << "Sticky switching depth is more than layout count -1, adjusting..." ;
137 m_stickySwitchingDepth
= m_layouts
.count() - 1;
141 m_stickySwitching
= false; //TODO: so far we can't do sticky with xkb switching groups...
144 m_resetOldOptions
= config
.readEntry("ResetOldOptions", true);
145 QString options
= config
.readEntry("Options", "");
146 m_options
= options
.split(OPTIONS_SEPARATOR
, QString::SkipEmptyParts
);
147 kDebug() << "Xkb options:" /*(enabled=" << m_enableXkbOptions << "): "*/ << m_options
;
152 static QString
addNum(const QString
& str
, int n
)
154 QString
format("%1%2");
155 if( str
.length() >= 3 ) return format
.arg(str
.left(2)).arg(n
);
156 return format
.arg(str
).arg(n
);
159 void KxkbConfig::updateDisplayNames()
161 for(int i
=0; i
<m_layouts
.count(); i
++) {
162 LayoutUnit
& lu
= m_layouts
[i
];
164 for(int j
=i
; j
<m_layouts
.count(); j
++) {
165 LayoutUnit
& lu2
= m_layouts
[j
];
166 if( i
!= j
&& lu
.layout
== lu2
.layout
) {
168 lu
.setDisplayName( addNum(lu
.layout
, 1) );
169 lu2
.setDisplayName( addNum(lu2
.layout
, cnt
) );
175 void KxkbConfig::setConfiguredLayouts(XkbConfig xkbConfig
)
177 kDebug() << "resetting layouts to " << xkbConfig
.layouts
.count() << " active in X server";
179 m_layouts
<< xkbConfig
.layouts
;
181 m_options
<< xkbConfig
.options
;
183 updateDisplayNames();
186 void KxkbConfig::save()
188 KConfigGroup
config(KSharedConfig::openConfig( "kxkbrc", KConfig::NoGlobals
), "Layout");
190 config
.writeEntry("Model", m_model
);
192 // config.writeEntry("EnableXkbOptions", m_enableXkbOptions );
193 config
.writeEntry("IndicatorOnly", m_indicatorOnly
);
194 config
.writeEntry("ResetOldOptions", m_resetOldOptions
);
195 config
.writeEntry("Options", m_options
.join(OPTIONS_SEPARATOR
) );
197 QStringList layoutList
;
198 QStringList displayNamesList
;
200 QList
<LayoutUnit
>::ConstIterator it
;
201 for(it
= m_layouts
.constBegin(); it
!= m_layouts
.constEnd(); ++it
) {
202 const LayoutUnit
& layoutUnit
= *it
;
204 layoutList
.append( layoutUnit
.toPair() );
206 QString displayName
= layoutUnit
.getDisplayName();
207 kDebug() << " displayName " << layoutUnit
.toPair() << " : " << displayName
;
208 //if( displayName.isEmpty() == false && displayName != layoutUnit.layout ) {
209 // displayName = QString("%1:%2").arg(layoutUnit.toPair(), displayName);
210 displayNamesList
.append( displayName
);
214 config
.writeEntry("LayoutList", layoutList
);
215 kDebug() << "Saving Layouts: " << layoutList
;
217 // if( displayNamesList.empty() == false )
218 config
.writeEntry("DisplayNames", displayNamesList
);
220 // config.deleteEntry("DisplayNames");
222 config
.writeEntry("Use", m_useKxkb
);
223 config
.writeEntry("ShowSingle", m_showSingle
);
224 config
.writeEntry("ShowFlag", m_showFlag
);
226 config
.writeEntry("SwitchMode", switchModes
[m_switchingPolicy
]);
228 #ifdef STICKY_SWITCHING
229 config
.writeEntry("StickySwitching", m_stickySwitching
);
230 config
.writeEntry("StickySwitchingDepth", m_stickySwitchingDepth
);
236 void KxkbConfig::setDefaults()
238 m_model
= DEFAULT_MODEL
;
240 // m_enableXkbOptions = false;
241 m_resetOldOptions
= false;
245 m_layouts
.append( DEFAULT_LAYOUT_UNIT
);
248 m_indicatorOnly
= false;
249 m_showSingle
= false;
252 m_switchingPolicy
= SWITCH_POLICY_GLOBAL
;
254 m_stickySwitching
= false;
255 m_stickySwitchingDepth
= 2;
258 QStringList
KxkbConfig::getLayoutStringList(/*bool compact*/)
260 QStringList layoutList
;
261 for(QList
<LayoutUnit
>::ConstIterator it
= m_layouts
.constBegin(); it
!= m_layouts
.constEnd(); ++it
) {
262 const LayoutUnit
& layoutUnit
= *it
;
263 layoutList
.append( layoutUnit
.toPair() );
269 QString
LayoutUnit::getDefaultDisplayName(const QString
& layout
, const QString
& /*variant*/)
271 return layout
.left(MAX_LABEL_LEN
);
272 // if( layoutUnit.variant.isEmpty() )
273 // return getDefaultDisplayName( layoutUnit.layout );
275 // QString displayName = layoutUnit.layout.left(2);
276 // if( single == false )
277 // displayName += layoutUnit.variant.left(1);
278 // return displayName;
282 * @brief Gets the single layout part of a layout(variant) string
283 * @param[in] layvar String in form layout(variant) to parse
284 * @return The layout found in the string
286 const QString
LayoutUnit::parseLayout(const QString
&layvar
)
288 static const char* LAYOUT_PATTERN
= "[a-zA-Z0-9_/-]*";
289 QString varLine
= layvar
.trimmed();
290 QRegExp
rx(LAYOUT_PATTERN
);
291 int pos
= rx
.indexIn(varLine
, 0);
292 int len
= rx
.matchedLength();
294 if( pos
< 0 || len
< 2 )
296 // kDebug() << "getLayout: " << varLine.mid(pos, len);
297 return varLine
.mid(pos
, len
);
301 * @brief Gets the single variant part of a layout(variant) string
302 * @param[in] layvar String in form layout(variant) to parse
303 * @return The variant found in the string, no check is performed
305 const QString
LayoutUnit::parseVariant(const QString
&layvar
)
307 static const char* VARIANT_PATTERN
= "\\([a-zA-Z0-9_-]*\\)";
308 QString varLine
= layvar
.trimmed();
309 QRegExp
rx(VARIANT_PATTERN
);
310 int pos
= rx
.indexIn(varLine
, 0);
311 int len
= rx
.matchedLength();
313 if( pos
< 2 || len
< 2 )
315 return varLine
.mid(pos
+1, len
-2);