not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / kxkb / extension.cpp
bloba1e28453e2bad58576a8f01c67c8890fbdc2ed80
1 /*
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.
19 #include <string.h>
20 #include <errno.h>
23 #include <QX11Info>
24 #include <QDir>
25 #include <QFile>
27 #include <kdebug.h>
28 #include <kstandarddirs.h>
29 #include <kprocess.h>
31 #include <X11/Xatom.h>
32 #include <X11/Xos.h>
33 #include <X11/Xlib.h>
34 #include <X11/XKBlib.h>
35 #ifndef HAVE_XKLAVIER
36 #include <X11/extensions/XKBfile.h>
37 #endif
39 #include "extension.h"
42 static const char* SETXKBMAP_SEPARATOR=",";
44 QString XKBExtension::m_setxkbmap_exe = "";
46 XKBExtension::XKBExtension(Display *d)
48 if ( d == NULL )
49 d = QX11Info::display();
50 m_dpy = d;
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;
64 return false;
67 // Verify the X server has matching XKB extension.
69 int opcode_rtrn;
70 int error_rtrn;
71 // int xkb_opcode;
72 if (!XkbQueryExtension(m_dpy, &opcode_rtrn, &xkb_opcode, &error_rtrn,
73 &major, &minor))
75 kError() << "X server XKB extension " << major << '.' << minor <<
76 " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl;
77 return false;
80 #ifndef HAVE_XKLAVIER
81 // Do it, or face horrible memory corrupting bugs
82 ::XkbInitAtoms(NULL);
83 #endif
85 int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask;
86 if( !XkbSelectEvents(m_dpy, XkbUseCoreKbd, eventMask, eventMask) ) {
87 kDebug() << "Couldn't select desired XKB events";
88 return false;
91 kDebug() << "XKB inited";
93 return true;
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 )
113 return "";
115 QString cmd = "setxkbmap";
116 if( resetOld )
117 cmd += " -option";
119 if( ! options.empty() ) {
120 cmd += " -option ";
121 cmd += options.join(SETXKBMAP_SEPARATOR);
123 return cmd;
126 bool XKBExtension::setXkbOptions(const QStringList& options, bool resetOld)
128 kDebug() << "Setting XKB options " << options.join(SETXKBMAP_SEPARATOR);
130 if( options.empty() && ! resetOld )
131 return true;
133 getSetxkbmapExe();
134 if( m_setxkbmap_exe.isEmpty() )
135 return false;
137 KProcess p;
138 p << m_setxkbmap_exe;
140 if( resetOld )
141 p << "-option";
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() )
167 return "";
169 QString cmd = "setxkbmap";
171 if( ! model.isEmpty() ) {
172 cmd += " -model ";
173 cmd += model;
176 cmd += " -layout ";
177 cmd += layouts.join(SETXKBMAP_SEPARATOR);
179 if( ! variants.empty() ) {
180 cmd += " -variant ";
181 cmd += variants.join(SETXKBMAP_SEPARATOR);
183 return cmd;
186 bool XKBExtension::setLayoutGroups(const QString& model, const QStringList& layouts, const QStringList& variants,
187 const QStringList& options, bool resetOldOptions)
189 if( layouts.empty() )
190 return false;
192 getSetxkbmapExe();
193 if( m_setxkbmap_exe.isEmpty() )
194 return false;
196 KProcess p;
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 )
209 p << "-option";
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);
222 return setxkbmapOk;
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);