diff options
-rw-r--r-- | kxkb/eventsrc | 5 | ||||
-rw-r--r-- | kxkb/extension.cpp | 183 | ||||
-rw-r--r-- | kxkb/extension.h | 54 | ||||
-rw-r--r-- | kxkb/kcmlayout.cpp | 67 | ||||
-rw-r--r-- | kxkb/kcmlayout.h | 6 | ||||
-rw-r--r-- | kxkb/kxkb.cpp | 49 | ||||
-rw-r--r-- | kxkb/kxkb.h | 2 | ||||
-rw-r--r-- | kxkb/kxkbconfig.cpp | 87 | ||||
-rw-r--r-- | kxkb/kxkbconfig.h | 6 |
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: |