summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kxkb/eventsrc5
-rw-r--r--kxkb/extension.cpp183
-rw-r--r--kxkb/extension.h54
-rw-r--r--kxkb/kcmlayout.cpp67
-rw-r--r--kxkb/kcmlayout.h6
-rw-r--r--kxkb/kxkb.cpp49
-rw-r--r--kxkb/kxkb.h2
-rw-r--r--kxkb/kxkbconfig.cpp87
-rw-r--r--kxkb/kxkbconfig.h6
9 files changed, 374 insertions, 85 deletions
diff --git a/kxkb/eventsrc b/kxkb/eventsrc
index 1e06d70c3..e80332fbe 100644
--- a/kxkb/eventsrc
+++ b/kxkb/eventsrc
@@ -10,4 +10,9 @@ default_presentation=16
[Error]
Name=Keyboard layout switching error
Comment=Error while attempting to switch the keyboard layout
+default_presentation=16
+
+[ExternalChange]
+Name=External configuration change
+Comment=An external application has modified the active keyboard configuration
default_presentation=16 \ No newline at end of file
diff --git a/kxkb/extension.cpp b/kxkb/extension.cpp
index a7da41ead..c238811fd 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,6 +34,7 @@
#include <tqmap.h>
#include <tqfile.h>
#include <tqdir.h>
+#include <tqtimer.h>
#include <kdebug.h>
#include <kstandarddirs.h>
@@ -21,58 +51,78 @@
#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.lock();
+ kdDebug() << "[kxkb-extension] Initializing Xkb extension" << endl;
+ m_dpy = tqt_xdisplay();
- int major = XkbMajorVersion;
- int minor = XkbMinorVersion;
+ // 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;
- }
+ 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;
- }
+ 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);
+
+ XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbNewKeyboardNotify,
+ XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
- // watch group change events
- XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify,
- XkbAllStateComponentsMask, XkbGroupStateMask);
- return true;
+// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" );
+// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
+ m_tempDir = locateLocal("tmp", "");
+
+ m_configureLock.unlock();
+ return true;
}
XKBExtension::~XKBExtension()
@@ -81,8 +131,22 @@ XKBExtension::~XKBExtension()
deletePrecompiledLayouts();*/
}
+void XKBExtension::safeConfigureLockRelease()
+{
+ // Without this protection in place KXkb would react to configuration
+ // changes caused by itself
+ TQTimer::singleShot(500, this, TQ_SLOT(configureDone()));
+}
+
+void XKBExtension::configureDone()
+{
+ m_configureLock.unlock();
+}
+
bool XKBExtension::setXkbOptions(const XkbOptions options)
{
+ m_configureLock.lock();
+
TQString exe = TDEGlobal::dirs()->findExe("setxkbmap");
if (exe.isEmpty())
{
@@ -121,7 +185,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)
@@ -144,6 +209,7 @@ bool XKBExtension::setXkbOptions(const XkbOptions 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;
+ m_configureLock.unlock();
return true;
}
@@ -151,42 +217,55 @@ bool XKBExtension::setXkbOptions(const XkbOptions options)
p.start(TDEProcess::Block);
+ safeConfigureLockRelease();
+
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) && vd.options)
+ {
+ 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 */
+// 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.tryLock())
+ {
+ return;
+ }
+ emit optionsChanged();
+ safeConfigureLockRelease();
+ }
}
#include "extension.moc"
diff --git a/kxkb/extension.h b/kxkb/extension.h
index 091cce582..0b82f70b5 100644
--- a/kxkb/extension.h
+++ b/kxkb/extension.h
@@ -1,8 +1,38 @@
+/*******************************************************************************
+
+ 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.
+
+*******************************************************************************/
+
#ifndef __EXTENSION_H__
#define __EXTENSION_H__
#include <X11/Xlib.h>
+
#include <tqobject.h>
+#include <tqmutex.h>
#include "kxkbconfig.h"
@@ -11,24 +41,40 @@ class XKBExtension : public TQObject
TQ_OBJECT
public:
- XKBExtension(Display *display=NULL);
+ static XKBExtension *the();
~XKBExtension();
+
+ XKBExtension(XKBExtension const&) = delete;
+ void operator=(XKBExtension const&) = delete;
+
bool init();
- static bool setXkbOptions(const XkbOptions options);
- static TQString getServerOptions();
+ bool setXkbOptions(const XkbOptions options);
bool setGroup(uint group);
+
uint getGroup() const;
+ XkbOptions getServerOptions();
+
void processXEvent(XEvent *ev);
+ void safeConfigureLockRelease();
+
+private slots:
+ void configureDone();
+
+protected:
+ XKBExtension() {}
+
private:
- Display *m_dpy;
+ Display *m_dpy;
TQString m_tempDir;
int m_keycode;
static TQMap<TQString, FILE*> fileCache;
+ TQMutex m_configureLock;
signals:
void groupChanged(uint group);
+ void optionsChanged();
};
#endif
diff --git a/kxkb/kcmlayout.cpp b/kxkb/kcmlayout.cpp
index 94c7b7d49..aee98ff22 100644
--- a/kxkb/kcmlayout.cpp
+++ b/kxkb/kcmlayout.cpp
@@ -14,6 +14,7 @@
#include <tqbuttongroup.h>
#include <tqspinbox.h>
#include <tqvbox.h>
+#include <tqtimer.h>
#include <tdefontrequester.h>
#include <kcolorbutton.h>
@@ -190,8 +191,8 @@ LayoutConfig::LayoutConfig(TQWidget *parent, const char *name)
#include "kxkbbindings.cpp"
makeOptionsTab();
- load();
makeShortcutsTab();
+ TQTimer::singleShot(0, this, TQ_SLOT(load()));
}
@@ -205,11 +206,58 @@ LayoutConfig::~LayoutConfig()
void LayoutConfig::load()
{
m_kxkbConfig.load(KxkbConfig::LOAD_ALL_OPTIONS);
+
+ // Check if the active settings are tainted (i.e. modified by an external
+ // program) and present the user with a choice on whether they want to show
+ // the default or tainted options in the config dialog
+ XkbOptions options = XKBExtension::the()->getServerOptions();
+
+ // Either we load the active tainted configuration or the user-set
+ // KXkb configuration. Either way we want the 'Apply' and 'Ok' buttons
+ // to be active. In the first case, pressing either button will save
+ // the tainted configuration to disk; in the second case, pressing
+ // either button would apply the saved KXkb configuration.
+ // This is why we will pass `modified` as a parameter to initUI() below
+ // in order to ensure these GUI elements are accordingly enabled.
+ bool modified = m_kxkbConfig.setFromXkbOptions(options);
+ if (modified)
+ {
+ TQStringList taintedList;
+ int tainted = m_kxkbConfig.m_tainted;
+
+ // The i18n strings below need to match the tab names
+ if (tainted & KxkbConfig::TAINTED_LAYOUTS)
+ {
+ taintedList << i18n("Layout");
+ }
+
+ if (tainted & KxkbConfig::TAINTED_XKB_OPTS)
+ {
+ taintedList << i18n("Xkb Options");
+ }
+
+ int result = KMessageBox::warningYesNoList(this,
+ i18n("<qt>Some settings have been modified by an external "
+ "application (e.g. <tt>setxkbmap</tt>). Would you like to "
+ "import the currently active settings to the configuration "
+ "dialog?</qt>"),
+ taintedList,
+ i18n("Import current Xkb configuration?"),
+ i18n("Import"), i18n("Discard"),
+ "kxkbImportActiveSettings",
+ KMessageBox::Notify);
+
+ if (result == KMessageBox::No)
+ {
+ m_kxkbConfig.load(KxkbConfig::LOAD_BASIC_OPTIONS);
+ }
+ }
+
keys->readSettings();
- initUI();
+ initUI(modified);
}
-void LayoutConfig::initUI() {
+void LayoutConfig::initUI(bool modified) {
const char* modelName = m_rules->models()[m_kxkbConfig.m_model];
if( modelName == NULL )
modelName = DEFAULT_MODEL;
@@ -226,7 +274,6 @@ void LayoutConfig::initUI() {
for ( ; src_it.current(); ++src_it ) {
TQListViewItem* srcItem = src_it.current();
-
if ( layoutUnit.layout == src_it.current()->text(LAYOUT_COLUMN_MAP) ) { // check if current config knows about this layout
TQListViewItem* newItem = copyLVI(srcItem, widget->listLayoutsDst);
@@ -353,7 +400,7 @@ void LayoutConfig::initUI() {
updateOptionsCommand();
updateHotkeyCombo(true);
- emit TDECModule::changed( false );
+ emit TDECModule::changed(modified);
}
@@ -432,7 +479,8 @@ void LayoutConfig::save()
if (m_forceGrpOverwrite)
{
// First get all the server's options
- TQStringList srvOptions = TQStringList::split(",", XKBExtension::getServerOptions());
+ XkbOptions _opt = XKBExtension::the()->getServerOptions();
+ TQStringList srvOptions = TQStringList::split(",", _opt.options);
TQStringList newOptions;
// Then remove all grp: options
@@ -449,7 +497,7 @@ void LayoutConfig::save()
xkbOptions.options = newOptions.join(",");
xkbOptions.resetOld = true;
- if (!XKBExtension::setXkbOptions(xkbOptions))
+ if (!XKBExtension::the()->setXkbOptions(xkbOptions))
{
kdWarning() << "[LayoutConfig::save] Could not overwrite previous grp: options!" << endl;
}
@@ -1007,7 +1055,8 @@ void LayoutConfig::updateHotkeyCombo(bool initial) {
// Get server options first
if (initial || widget->xkbOptsMode->selectedId() == 1)
{
- TQStringList opts = TQStringList::split(",", XKBExtension::getServerOptions());
+ XkbOptions _opt = XKBExtension::the()->getServerOptions();
+ TQStringList opts = TQStringList::split(",", _opt.options);
for (TQStringList::Iterator it = opts.begin(); it != opts.end(); ++it)
{
TQString option(*it);
@@ -1267,7 +1316,7 @@ extern "C"
kapp->startServiceByDesktopName("kxkb");
}
else {
- if (!XKBExtension::setXkbOptions(m_kxkbConfig.getKXkbOptions())) {
+ if (!XKBExtension::the()->setXkbOptions(m_kxkbConfig.getKXkbOptions())) {
kdDebug() << "Setting XKB options failed!" << endl;
}
}
diff --git a/kxkb/kcmlayout.h b/kxkb/kcmlayout.h
index 256946ad1..0d2e153b2 100644
--- a/kxkb/kcmlayout.h
+++ b/kxkb/kcmlayout.h
@@ -23,11 +23,13 @@ public:
LayoutConfig(TQWidget *parent = 0L, const char *name = 0L);
virtual ~LayoutConfig();
+ void initUI(bool modified = false);
+ virtual TQString handbookDocPath() const;
+
+public slots:
void load();
void save();
void defaults();
- void initUI();
- virtual TQString handbookDocPath() const;
protected:
TQString createOptionString();
diff --git a/kxkb/kxkb.cpp b/kxkb/kxkb.cpp
index 8bced3fea..9db61278a 100644
--- a/kxkb/kxkb.cpp
+++ b/kxkb/kxkb.cpp
@@ -24,7 +24,6 @@ DESCRIPTION
*/
#include <unistd.h>
-#include <stdlib.h>
#include <assert.h>
#include <tqregexp.h>
@@ -70,13 +69,10 @@ KXKBApp::KXKBApp(bool allowStyles, bool GUIenabled)
m_tray(NULL),
kWinModule(NULL)
{
- X11Helper::initializeTranslations();
- m_extension = new XKBExtension();
- if( !m_extension->init() ) {
- kdDebug() << "xkb initialization failed, exiting..." << endl;
- ::exit(1);
- }
- connect(m_extension, TQ_SIGNAL(groupChanged(uint)), this, TQ_SLOT(slotGroupChanged(uint)));
+ X11Helper::initializeTranslations();
+ XKBExtension *xkb = XKBExtension::the();
+ connect(xkb, TQ_SIGNAL(groupChanged(uint)), this, TQ_SLOT(slotGroupChanged(uint)));
+ connect(xkb, TQ_SIGNAL(optionsChanged()), this, TQ_SLOT(slotXkbOptionsChanged()));
m_layoutOwnerMap = new LayoutMap(kxkbConfig);
@@ -97,7 +93,6 @@ KXKBApp::~KXKBApp()
{
delete m_tray;
delete m_rules;
- delete m_extension;
delete m_layoutOwnerMap;
delete kWinModule;
delete keys;
@@ -203,7 +198,7 @@ void KXKBApp::readSettings()
void KXKBApp::applyXkbOptions()
{
XkbOptions options = kxkbConfig.getKXkbOptions();
- if (!m_extension->setXkbOptions(options)) {
+ if (!XKBExtension::the()->setXkbOptions(options)) {
kdWarning() << "Setting XKB options failed!" << endl;
}
}
@@ -236,14 +231,14 @@ bool KXKBApp::setLayout(const LayoutUnit& layoutUnit)
bool KXKBApp::setLayout(const uint group)
{
// If this group is already set, just show the notification and return
- if (m_extension->getGroup() == group) {
+ if (XKBExtension::the()->getGroup() == group) {
if (kxkbConfig.m_enableNotify) {
showLayoutNotification();
}
return true;
}
- bool ok = m_extension->setGroup(group);
+ bool ok = XKBExtension::the()->setGroup(group);
if (!ok) {
TQString layout = kxkbConfig.m_layouts[group].toPair();
if (m_tray) {
@@ -317,7 +312,32 @@ void KXKBApp::slotGroupChanged(uint group)
}
}
-void KXKBApp::showLayoutNotification() {
+void KXKBApp::slotXkbOptionsChanged()
+{
+ TQTimer::singleShot(500, this, TQ_SLOT(syncXkbOptions()));
+}
+
+void KXKBApp::syncXkbOptions()
+{
+ XkbOptions options = XKBExtension::the()->getServerOptions();
+ if (kxkbConfig.setFromXkbOptions(options))
+ {
+ m_layoutOwnerMap->reset();
+ m_tray->initLayoutList(kxkbConfig.m_layouts, *m_rules);
+
+ // This event is not related to layout switching hence the notification-related
+ // options do not apply here, but only options from the system notifications
+ // control module.
+ KNotifyClient::event(
+ m_tray->winId(), "ExternalChange",
+ i18n("An external application has modified the active keyboard configuration"));
+ }
+
+ slotGroupChanged(XKBExtension::the()->getGroup());
+}
+
+void KXKBApp::showLayoutNotification()
+{
bool useKMilo = kxkbConfig.m_notifyUseKMilo && isKMiloAvailable(),
notificationSent = false;
@@ -396,7 +416,6 @@ void KXKBApp::windowChanged(WId winId)
}
}
-
void KXKBApp::slotSettingsChanged(int category)
{
if (category == TDEApplication::SETTINGS_SHORTCUTS) {
@@ -408,7 +427,7 @@ void KXKBApp::slotSettingsChanged(int category)
bool KXKBApp::x11EventFilter(XEvent *e) {
// let the extension process the event and emit signals if necessary
- m_extension->processXEvent(e);
+ XKBExtension::the()->processXEvent(e);
return TDEApplication::x11EventFilter(e);
}
diff --git a/kxkb/kxkb.h b/kxkb/kxkb.h
index b5ac7b7bf..9e10a6c4c 100644
--- a/kxkb/kxkb.h
+++ b/kxkb/kxkb.h
@@ -74,6 +74,7 @@ protected slots:
void menuActivated(int id);
void windowChanged(WId winId);
void slotGroupChanged(uint group);
+ void slotXkbOptionsChanged();
void slotSettingsChanged(int category);
void showLayoutNotification();
@@ -83,6 +84,7 @@ protected slots:
void readSettings();
void applyXkbOptions();
+ void syncXkbOptions();
private:
void initTray();
diff --git a/kxkb/kxkbconfig.cpp b/kxkb/kxkbconfig.cpp
index 166dab174..42de6d8ce 100644
--- a/kxkb/kxkbconfig.cpp
+++ b/kxkb/kxkbconfig.cpp
@@ -33,9 +33,12 @@ const char* DEFAULT_MODEL = "pc104";
void KxkbConfig::load(int loadMode)
{
// INITIAL OPTIONS (loaded regardless of whether KXkb is enabled)
+
TDEConfig *config = new TDEConfig("kxkbrc", true, false);
config->setGroup("Layout");
+ m_tainted = TAINTED_NONE;
+
m_useKxkb = config->readBoolEntry("Use", false);
m_resetOldOptions = config->readBoolEntry("ResetOldOptions", true);
@@ -46,7 +49,8 @@ void KxkbConfig::load(int loadMode)
return;
}
- // ALL OTHER OPTIONS (loaded only when KXkb is enabled)
+ // BASIC OPTIONS (passed to setxkbmap, can be tainted)
+
m_model = config->readEntry("Model", DEFAULT_MODEL);
// Layouts
@@ -93,6 +97,13 @@ void KxkbConfig::load(int loadMode)
}
}
+ if (loadMode == LOAD_BASIC_OPTIONS)
+ {
+ return;
+ }
+
+ // ALL OTHER OPTIONS (of interest only to KXkb itself)
+
// Tray indicator
m_showSingle = config->readBoolEntry("ShowSingle", false);
@@ -169,6 +180,8 @@ void KxkbConfig::load(int loadMode)
void KxkbConfig::save()
{
+ m_tainted = TAINTED_NONE;
+
TDEConfig *config = new TDEConfig("kxkbrc", false, false);
config->setGroup("Layout");
@@ -245,6 +258,8 @@ void KxkbConfig::save()
void KxkbConfig::setDefaults()
{
+ m_tainted = TAINTED_NONE;
+
m_model = DEFAULT_MODEL;
m_resetOldOptions = true;
@@ -267,6 +282,75 @@ void KxkbConfig::setDefaults()
m_stickySwitchingDepth = 2;
}
+bool KxkbConfig::setFromXkbOptions(XkbOptions options)
+{
+ XkbOptions curOptions = getKXkbOptions();
+ uint tainted = TAINTED_NONE;
+
+ // We need to fix the variants string if it is empty, otherwise the
+ // comparison below will often wrongly assume that the variants have
+ // changed
+ if (options.variants.isNull())
+ {
+ for (int i = 0; i < options.layouts.contains(","); ++i)
+ {
+ options.variants += ",";
+ }
+ }
+
+ // Check if keyboard layout options have changed
+ if ((options.model != curOptions.model && !options.model.isNull())
+ || (options.layouts != curOptions.layouts)
+ || (options.variants != curOptions.variants))
+ {
+ tainted |= TAINTED_LAYOUTS;
+ kdWarning() << "Keyboard layouts modified by external application!" << endl;
+
+ kdDebug() << "model " << curOptions.model << "=>" << options.model << endl;
+ kdDebug() << "layouts " << curOptions.layouts << "=>" << options.layouts << endl;
+ kdDebug() << "variants " << curOptions.variants << "=>" << options.variants << endl;
+ m_model = options.model;
+
+ m_layouts.clear();
+
+ TQStringList layouts = TQStringList::split(",", options.layouts, true);
+ TQStringList variants = TQStringList::split(",", options.variants, true);
+ TQStringList::Iterator lit = layouts.begin();
+ TQStringList::Iterator vit = variants.begin();
+
+ while (lit != layouts.end())
+ {
+ TQString layout = *lit;
+ TQString variant = vit != variants.end() ? *vit : TQString::null;
+ m_layouts.append(LayoutUnit(layout, variant));
+
+ ++lit;
+ if (vit != variants.end())
+ {
+ ++vit;
+ }
+ }
+ }
+
+ // Check if Xkb options have changed
+ if (options.options != options.options || options.resetOld != options.resetOld)
+ {
+ tainted |= TAINTED_XKB_OPTS;
+ kdWarning() << "Xkb options modified by external application!" << endl;
+ m_options = options.options;
+ m_resetOldOptions = options.resetOld;
+ }
+
+ if (tainted != TAINTED_NONE)
+ {
+ kdDebug() << "Loaded tainted config with " << m_layouts.count()
+ << " layouts" << endl;
+ m_tainted = tainted;
+ }
+
+ return (tainted != TAINTED_NONE);
+}
+
TQStringList KxkbConfig::getLayoutStringList(/*bool compact*/)
{
TQStringList layoutList;
@@ -325,7 +409,6 @@ const XkbOptions KxkbConfig::getKXkbOptions() {
options.variants = variants.join(",");
options.model = m_model;
options.options = m_options;
- kdDebug() << "[getKXkbOptions] options: " << m_options << endl;
options.resetOld = m_resetOldOptions;
return options;
}
diff --git a/kxkb/kxkbconfig.h b/kxkb/kxkbconfig.h
index a365ef252..229824b77 100644
--- a/kxkb/kxkbconfig.h
+++ b/kxkb/kxkbconfig.h
@@ -45,7 +45,8 @@ extern const char* DEFAULT_MODEL;
class KxkbConfig
{
public:
- enum { LOAD_INIT_OPTIONS, LOAD_ALL_OPTIONS };
+ enum { LOAD_INIT_OPTIONS, LOAD_BASIC_OPTIONS, LOAD_ALL_OPTIONS };
+ enum { TAINTED_NONE = 0, TAINTED_LAYOUTS, TAINTED_XKB_OPTS };
bool m_useKxkb;
bool m_showSingle;
@@ -74,6 +75,8 @@ public:
TQString m_options;
TQValueList<LayoutUnit> m_layouts;
+ uint m_tainted;
+
void load(int loadMode);
void save();
void setDefaults();
@@ -82,6 +85,7 @@ public:
static TQString getDefaultDisplayName(const TQString& code_);
static TQString getDefaultDisplayName(const LayoutUnit& layoutUnit, bool single=false);
+ bool setFromXkbOptions(XkbOptions options);
const XkbOptions getKXkbOptions();
private: