|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
|
|
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <X11/Xos.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/XKBlib.h>
|
|
|
|
#include <X11/extensions/XKBfile.h>
|
|
|
|
#include <X11/extensions/XKBrules.h>
|
|
|
|
#include <X11/extensions/XKBgeom.h>
|
|
|
|
#include <X11/extensions/XKM.h>
|
|
|
|
|
|
|
|
#include "extension.h"
|
|
|
|
|
|
|
|
|
|
|
|
static TQString getLayoutKey(const TQString& layout, const TQString& variant)
|
|
|
|
{
|
|
|
|
return layout + "." + variant;
|
|
|
|
}
|
|
|
|
|
|
|
|
XKBExtension::XKBExtension(Display *d)
|
|
|
|
{
|
|
|
|
if ( d == NULL )
|
|
|
|
d = tqt_xdisplay();
|
|
|
|
m_dpy = d;
|
|
|
|
|
|
|
|
// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" );
|
|
|
|
// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
|
|
|
|
m_tempDir = locateLocal("tmp", "");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XKBExtension::init()
|
|
|
|
{
|
|
|
|
// Verify the Xlib has matching XKB extension.
|
|
|
|
|
|
|
|
int major = XkbMajorVersion;
|
|
|
|
int minor = XkbMinorVersion;
|
|
|
|
|
|
|
|
if (!XkbLibraryVersion(&major, &minor))
|
|
|
|
{
|
|
|
|
kdError() << "[kxkb-extension] Xlib XKB extension " << major << '.' << minor <<
|
|
|
|
" != " << XkbMajorVersion << '.' << XkbMinorVersion << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify the X server has matching XKB extension.
|
|
|
|
|
|
|
|
int opcode_rtrn;
|
|
|
|
int error_rtrn;
|
|
|
|
int xkb_opcode;
|
|
|
|
if (!XkbQueryExtension(m_dpy, &opcode_rtrn, &xkb_opcode, &error_rtrn,
|
|
|
|
&major, &minor))
|
|
|
|
{
|
|
|
|
kdError() << "[kxkb-extension] X server XKB extension " << major << '.' << minor <<
|
|
|
|
" != " << XkbMajorVersion << '.' << XkbMinorVersion << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do it, or face horrible memory corrupting bugs
|
|
|
|
::XkbInitAtoms(NULL);
|
|
|
|
|
|
|
|
// watch group change events
|
|
|
|
XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify,
|
|
|
|
XkbAllStateComponentsMask, XkbGroupStateMask);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
XKBExtension::~XKBExtension()
|
|
|
|
{
|
|
|
|
/* if( m_compiledLayoutFileNames.isEmpty() == false )
|
|
|
|
deletePrecompiledLayouts();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XKBExtension::setXkbOptions(const XkbOptions options)
|
|
|
|
{
|
|
|
|
TQString exe = TDEGlobal::dirs()->findExe("setxkbmap");
|
|
|
|
if (exe.isEmpty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
TDEProcess p;
|
|
|
|
p << exe;
|
|
|
|
|
|
|
|
if (!options.layouts.isEmpty())
|
|
|
|
{
|
|
|
|
p << "-layout";
|
|
|
|
p << options.layouts;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.variants.isEmpty())
|
|
|
|
{
|
|
|
|
p << "-variant";
|
|
|
|
p << options.variants;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.model.isEmpty()) {
|
|
|
|
p << "-model";
|
|
|
|
p << options.model;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.resetOld) {
|
|
|
|
p << "-option";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.options.isEmpty()) {
|
|
|
|
if (options.resetOld)
|
|
|
|
{
|
|
|
|
p << "-option" << options.options;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Avoid duplication of options in Append mode
|
|
|
|
TQStringList srvOptions = TQStringList::split(",", XKBExtension::getServerOptions());
|
|
|
|
TQStringList kxkbOptions = TQStringList::split(",", options.options);
|
|
|
|
TQStringList newOptions;
|
|
|
|
for (TQStringList::Iterator it = kxkbOptions.begin(); it != kxkbOptions.end(); ++it)
|
|
|
|
{
|
|
|
|
TQString option(*it);
|
|
|
|
if (!srvOptions.contains(option))
|
|
|
|
{
|
|
|
|
newOptions << option;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!newOptions.isEmpty()) {
|
|
|
|
p << "-option" << newOptions.join(",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug() << "[setXkbOptions] Command: " << p.args() << endl;
|
|
|
|
|
|
|
|
p.start(TDEProcess::Block);
|
|
|
|
|
|
|
|
return p.normalExit() && (p.exitStatus() == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString XKBExtension::getServerOptions()
|
|
|
|
{
|
|
|
|
XkbRF_VarDefsRec vd;
|
|
|
|
if (XkbRF_GetNamesProp(tqt_xdisplay(), nullptr, &vd) && vd.options)
|
|
|
|
{
|
|
|
|
kdDebug() << "[kxkb-extension] Got server options " << vd.options << endl;
|
|
|
|
return TQString(vd.options);
|
|
|
|
}
|
|
|
|
return TQString::null;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XKBExtension::setGroup(unsigned int group)
|
|
|
|
{
|
|
|
|
kdDebug() << "[kxkb-extension] Setting group " << group << endl;
|
|
|
|
return XkbLockGroup( m_dpy, XkbUseCoreKbd, group );
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int XKBExtension::getGroup() const
|
|
|
|
{
|
|
|
|
XkbStateRec xkbState;
|
|
|
|
XkbGetState( m_dpy, XkbUseCoreKbd, &xkbState );
|
|
|
|
return xkbState.group;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Examines an X Event passed to it and takes actions if the event is of
|
|
|
|
* interest to KXkb */
|
|
|
|
void XKBExtension::processXEvent(XEvent *event) {
|
|
|
|
XkbEvent* xkb_event = (XkbEvent*)event;
|
|
|
|
if (xkb_event->any.xkb_type == XkbStateNotify) {
|
|
|
|
emit groupChanged(xkb_event->state.group);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "extension.moc"
|