2 * Copyright (C) 2003-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.
28 #include <kstandarddirs.h>
31 #include <X11/Xatom.h>
34 #include <X11/XKBlib.h>
36 #include <X11/extensions/XKBfile.h>
39 #include "extension.h"
42 static const char* SETXKBMAP_SEPARATOR
=",";
44 QString
XKBExtension::m_setxkbmap_exe
= "";
46 XKBExtension::XKBExtension(Display
*d
)
49 d
= QX11Info::display();
53 bool XKBExtension::init()
55 // Verify the Xlib has matching XKB extension.
57 int major
= XkbMajorVersion
;
58 int minor
= XkbMinorVersion
;
60 if (!XkbLibraryVersion(&major
, &minor
))
62 kError() << "Xlib XKB extension " << major
<< '.' << minor
<<
63 " != " << XkbMajorVersion
<< '.' << XkbMinorVersion
<< endl
;
67 // Verify the X server has matching XKB extension.
72 if (!XkbQueryExtension(m_dpy
, &opcode_rtrn
, &xkb_opcode
, &error_rtrn
,
75 kError() << "X server XKB extension " << major
<< '.' << minor
<<
76 " != " << XkbMajorVersion
<< '.' << XkbMinorVersion
<< endl
;
81 // Do it, or face horrible memory corrupting bugs
85 int eventMask
= XkbNewKeyboardNotifyMask
| XkbStateNotifyMask
;
86 if( !XkbSelectEvents(m_dpy
, XkbUseCoreKbd
, eventMask
, eventMask
) ) {
87 kDebug() << "Couldn't select desired XKB events";
91 kDebug() << "XKB inited";
96 XKBExtension::~XKBExtension()
100 QString
XKBExtension::getSetxkbmapExe()
102 if( m_setxkbmap_exe
.isEmpty() ) {
103 m_setxkbmap_exe
= KGlobal::dirs()->findExe("setxkbmap");
104 if( m_setxkbmap_exe
.isEmpty() )
105 kError() << "Can't find setxkbmap" << endl
;
107 return m_setxkbmap_exe
;
110 QString
XKBExtension::getXkbOptionsCommand(const QStringList
& options
, bool resetOld
)
112 if( options
.empty() && ! resetOld
)
115 QString cmd
= "setxkbmap";
119 if( ! options
.empty() ) {
121 cmd
+= options
.join(SETXKBMAP_SEPARATOR
);
126 bool XKBExtension::setXkbOptions(const QStringList
& options
, bool resetOld
)
128 kDebug() << "Setting XKB options " << options
.join(SETXKBMAP_SEPARATOR
);
130 if( options
.empty() && ! resetOld
)
134 if( m_setxkbmap_exe
.isEmpty() )
138 p
<< m_setxkbmap_exe
;
142 p
<< "-option" << options
.join(SETXKBMAP_SEPARATOR
);
144 kDebug() << "executing" << p
.program().join(" ");
146 return p
.execute() == 0;
149 void XKBExtension::executeXmodmap(const QString
& configFileName
)
151 if( QFile(configFileName
).exists() ) {
152 QString xmodmap_exe
= KGlobal::dirs()->findExe("xmodmap");
153 if( ! xmodmap_exe
.isEmpty() ) {
154 KProcess xmodmapProcess
;
155 xmodmapProcess
<< xmodmap_exe
;
156 xmodmapProcess
<< configFileName
;
157 kDebug() << "executing" << xmodmapProcess
.program().join(" ");
158 xmodmapProcess
.execute();
164 QString
XKBExtension::getLayoutGroupsCommand(const QString
& model
, const QStringList
& layouts
, const QStringList
& variants
)
166 if( layouts
.empty() )
169 QString cmd
= "setxkbmap";
171 if( ! model
.isEmpty() ) {
177 cmd
+= layouts
.join(SETXKBMAP_SEPARATOR
);
179 if( ! variants
.empty() ) {
181 cmd
+= variants
.join(SETXKBMAP_SEPARATOR
);
186 bool XKBExtension::setLayoutGroups(const QString
& model
, const QStringList
& layouts
, const QStringList
& variants
,
187 const QStringList
& options
, bool resetOldOptions
)
189 if( layouts
.empty() )
193 if( m_setxkbmap_exe
.isEmpty() )
197 p
<< m_setxkbmap_exe
;
199 if( ! model
.isEmpty() )
200 p
<< "-model" << model
;
202 p
<< "-layout" << layouts
.join(SETXKBMAP_SEPARATOR
);
204 if( ! variants
.empty() )
205 p
<< "-variant" << variants
.join(SETXKBMAP_SEPARATOR
);
207 if( ! options
.empty() ) {
208 if( resetOldOptions
)
210 p
<< "-option" << options
.join(SETXKBMAP_SEPARATOR
);
213 kDebug() << "executing" << p
.program().join(" ");
215 bool setxkbmapOk
= (p
.execute() == 0);
217 // QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap");
218 // executeXmodmap(configFileName);
219 QString configFileName
= QDir::home().filePath(".Xmodmap");
220 executeXmodmap(configFileName
);
225 bool XKBExtension::setGroup(unsigned int group
)
227 // kDebug() << "Setting group " << group;
228 return XkbLockGroup( m_dpy
, XkbUseCoreKbd
, group
);
231 unsigned int XKBExtension::getGroup() const
233 XkbStateRec xkbState
;
234 XkbGetState( m_dpy
, XkbUseCoreKbd
, &xkbState
);
235 return xkbState
.group
;
238 bool XKBExtension::isGroupSwitchEvent(XEvent
* event
)
240 XkbEvent
*xkbEvent
= (XkbEvent
*) event
;
241 #define GROUP_CHANGE_MASK \
242 ( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask )
244 return xkbEvent
->any
.xkb_type
== XkbStateNotify
&& xkbEvent
->state
.changed
& GROUP_CHANGE_MASK
;
247 bool XKBExtension::isLayoutSwitchEvent(XEvent
* event
)
249 XkbEvent
*xkbEvent
= (XkbEvent
*) event
;
251 return //( (xkbEvent->any.xkb_type == XkbMapNotify) && (xkbEvent->map.changed & XkbKeySymsMask) ) ||
252 /* || ( (xkbEvent->any.xkb_type == XkbNamesNotify) && (xkbEvent->names.changed & XkbGroupNamesMask) || )*/
253 (xkbEvent
->any
.xkb_type
== XkbNewKeyboardNotify
);