summaryrefslogtreecommitdiffstats
path: root/kxkb/extension.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kxkb/extension.cpp')
-rw-r--r--kxkb/extension.cpp214
1 files changed, 161 insertions, 53 deletions
diff --git a/kxkb/extension.cpp b/kxkb/extension.cpp
index 8197043aa..a9efb8226 100644
--- a/kxkb/extension.cpp
+++ b/kxkb/extension.cpp
@@ -1,3 +1,32 @@
+/*******************************************************************************
+
+ Xkb extension for KXkb
+ Copyright © 2009-2025 Trinity Desktop project
+ Copyright © 2001 S.R. Haque <[email protected]>
+
+ Derived from an original by Matthias H�zer-Klpfel released under the QPL.
+
+ Some portions come from kkbswitch released under the GNU GPL v2 (or later).
+ Copyright © 2001 Leonid Zeitlin <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*******************************************************************************/
+
+#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -5,10 +34,13 @@
#include <tqmap.h>
#include <tqfile.h>
#include <tqdir.h>
+#include <tqtimer.h>
#include <kdebug.h>
+#include <tdeapplication.h>
#include <kstandarddirs.h>
#include <tdeprocess.h>
+#include <dcopclient.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
@@ -21,58 +53,80 @@
#include "extension.h"
+extern "C"
+{
+ static int IgnoreXError(Display *, XErrorEvent *) { return 0; }
+}
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;
+static XKBExtension *xkbExtension = nullptr;
-// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" );
-// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
- m_tempDir = locateLocal("tmp", "");
+XKBExtension *XKBExtension::the()
+{
+ if (!xkbExtension)
+ {
+ xkbExtension = new XKBExtension;
+ if (!xkbExtension->init())
+ {
+ kdFatal() << "xkb initialization failed, exiting..." << endl;
+ ::exit(1);
+ }
+ }
+ return xkbExtension;
}
bool XKBExtension::init()
{
- // Verify the Xlib has matching XKB extension.
+ m_configureLock = 0;
+ acquireConfigureLock();
- int major = XkbMajorVersion;
- int minor = XkbMinorVersion;
+ kdDebug() << "[kxkb-extension] Initializing Xkb extension" << endl;
+ m_dpy = tqt_xdisplay();
- if (!XkbLibraryVersion(&major, &minor))
- {
- kdError() << "[kxkb-extension] Xlib XKB extension " << major << '.' << minor <<
- " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl;
- return false;
- }
+ // Verify the Xlib has matching XKB extension.
+ int major = XkbMajorVersion;
+ int minor = XkbMinorVersion;
- // Verify the X server has matching XKB extension.
+ if (!XkbLibraryVersion(&major, &minor))
+ {
+ kdError() << "[kxkb-extension] Xlib XKB extension " << major << '.' << minor <<
+ " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl;
+ return false;
+ }
- 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;
- }
+ // 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);
+ ::XkbInitAtoms(nullptr);
+
+ // Watch for interesting events
+ XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify,
+ XkbAllStateComponentsMask, XkbGroupStateMask);
- // watch group change events
- XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify,
- XkbAllStateComponentsMask, XkbGroupStateMask);
+ XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbNewKeyboardNotify,
+ XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
+
+
+// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" );
+// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
+ m_tempDir = locateLocal("tmp", "");
- return true;
+ releaseConfigureLock();
+ return true;
}
XKBExtension::~XKBExtension()
@@ -81,11 +135,32 @@ XKBExtension::~XKBExtension()
deletePrecompiledLayouts();*/
}
+void XKBExtension::acquireConfigureLock()
+{
+ ++m_configureLock;
+}
+
+void XKBExtension::releaseConfigureLock()
+{
+ // Without this protection in place KXkb would react to configuration
+ // changes caused by itself
+ TQTimer::singleShot(500, this, TQ_SLOT(slotReleaseConfigureLock()));
+}
+
+void XKBExtension::slotReleaseConfigureLock()
+{
+ --m_configureLock;
+}
+
bool XKBExtension::setXkbOptions(const XkbOptions options)
{
+ acquireConfigureLock();
+
TQString exe = TDEGlobal::dirs()->findExe("setxkbmap");
if (exe.isEmpty())
+ {
return false;
+ }
TDEProcess p;
p << exe;
@@ -119,7 +194,8 @@ bool XKBExtension::setXkbOptions(const XkbOptions options)
else
{
// Avoid duplication of options in Append mode
- TQStringList srvOptions = TQStringList::split(",", XKBExtension::getServerOptions());
+ XkbOptions _opt = getServerOptions();
+ TQStringList srvOptions = TQStringList::split(",", _opt.options);
TQStringList kxkbOptions = TQStringList::split(",", options.options);
TQStringList newOptions;
for (TQStringList::Iterator it = kxkbOptions.begin(); it != kxkbOptions.end(); ++it)
@@ -136,46 +212,78 @@ bool XKBExtension::setXkbOptions(const XkbOptions options)
}
}
+ if (p.args().count() < 2)
+ {
+ // Either the user has not configured any Xkb options or these options
+ // are already set and we are in append mode so we want to avoid
+ // duplicates
+ kdWarning() << "[setXkbOptions] No options need to be set" << endl;
+ slotReleaseConfigureLock(); // immediately release the lock
+ return true;
+ }
+
+ p << "-synch";
+
kdDebug() << "[setXkbOptions] Command: " << p.args() << endl;
p.start(TDEProcess::Block);
+ releaseConfigureLock();
+
return p.normalExit() && (p.exitStatus() == 0);
}
-TQString XKBExtension::getServerOptions()
+XkbOptions 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;
+ XkbOptions options;
+ XkbRF_VarDefsRec vd;
+ if (XkbRF_GetNamesProp(tqt_xdisplay(), nullptr, &vd))
+ {
+ options.model = vd.model;
+ options.layouts = vd.layout;
+ options.variants = vd.variant;
+ options.options = vd.options;
+ }
+ return options;
}
bool XKBExtension::setGroup(unsigned int group)
{
kdDebug() << "[kxkb-extension] Setting group " << group << endl;
- return XkbLockGroup( m_dpy, XkbUseCoreKbd, group );
+ return XkbLockGroup(m_dpy, XkbUseCoreKbd, group);
}
uint XKBExtension::getGroup() const
{
XkbStateRec xkbState;
- XkbGetState( m_dpy, XkbUseCoreKbd, &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 */
+bool XKBExtension::kcmlayoutRunning()
+{
+ return kapp->dcopClient()->isApplicationRegistered("TDECModuleProxy-keyboard_layout");
+}
+
+// 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 &&
- xkb_event->state.changed & XkbGroupStateMask)
- {
- emit groupChanged((uint)xkb_event->state.group);
- }
+ XkbEvent* xkb_event = (XkbEvent*)event;
+ if (xkb_event->any.xkb_type == XkbStateNotify && xkb_event->state.changed & XkbGroupStateMask)
+ {
+ emit groupChanged((uint)xkb_event->state.group);
+ }
+
+ else if (xkb_event->any.xkb_type == XkbNewKeyboardNotify)
+ {
+ if (m_configureLock > 0 || kcmlayoutRunning())
+ {
+ return;
+ }
+ acquireConfigureLock();
+ emit optionsChanged();
+ releaseConfigureLock();
+ }
}
-#include "extension.moc"
+#include "extension.moc" \ No newline at end of file