diff options
author | Mavridis Philippe <mavridisf@gmail.com> | 2023-01-06 15:30:57 +0200 |
---|---|---|
committer | Mavridis Philippe <mavridisf@gmail.com> | 2023-03-24 15:28:11 +0200 |
commit | a67db2d4847d798c01d4fd7584c5bb9297e109e3 (patch) | |
tree | 6cb5bb70f6201fa62dec021b92e838d32a6036ec /kxkb/extension.cpp | |
parent | b50ab13974adf6f16d72f172f0cf768a44c161da (diff) | |
download | tdebase-a67db2d4847d798c01d4fd7584c5bb9297e109e3.tar.gz tdebase-a67db2d4847d798c01d4fd7584c5bb9297e109e3.zip |
Kxkb: Improve layout switching
1) New layout switching approach
The new approach is based on the "grp" options group of Xkb
and so enables us to use predefined X11 layout (group) switching
hotkeys like "Caps Lock" or "Shift+Alt" (you can see the full list
in the Options tab). The added bonus to this is that we conform
to the Xkb setting.
The code lets Xkb handle the keyboard layout switching hotkey(s)
and is similar to the one that is used in kkbswitch, monitoring
for an Xkb group (layout) change event.
This solution required me to remove some hacky and obsolete code
which was there to support really old pre-XFree-4.2 era systems
and included the "include groups" hack.
This means that the "Enable latin layout" checkbox is now gone
and setxkbmap is only called when the keyboard layouts and/or
options are modified, and not for every layout change.
2) Common layout switching hotkeys combobox
A combobox was added to the first page of the Keyboard Layouts
KCM module. It provides to the users a quick way to set a layout
switching key combination. It also controls the "grp" group in
the Xkb tab.
A special note about this combobox is that, even if Append Mode
was selected in the Xkb Options tab, this hotkey will overwrite
previous hotkey options. This means that all grp: options will
be forced removed before applying the option from the combobox
(in contrast to specifying options via the Xkb Options tab,
which, in Append Mode, will not get overwritten until next login).
Signed-off-by: Mavridis Philippe <mavridisf@gmail.com>
Diffstat (limited to 'kxkb/extension.cpp')
-rw-r--r-- | kxkb/extension.cpp | 263 |
1 files changed, 32 insertions, 231 deletions
diff --git a/kxkb/extension.cpp b/kxkb/extension.cpp index 616167944..1b6895043 100644 --- a/kxkb/extension.cpp +++ b/kxkb/extension.cpp @@ -21,20 +21,11 @@ #include "extension.h" -TQMap<TQString, FILE*> XKBExtension::fileCache; //TODO: move to class? - - static TQString getLayoutKey(const TQString& layout, const TQString& variant) { return layout + "." + variant; } -TQString XKBExtension::getPrecompiledLayoutFilename(const TQString& layoutKey) -{ - TQString compiledLayoutFileName = m_tempDir + layoutKey + ".xkm"; - return compiledLayoutFileName; -} - XKBExtension::XKBExtension(Display *d) { if ( d == NULL ) @@ -76,16 +67,11 @@ bool XKBExtension::init() // Do it, or face horrible memory corrupting bugs ::XkbInitAtoms(NULL); - return true; -} + // watch group change events + XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify, + XkbAllStateComponentsMask, XkbGroupStateMask); -void XKBExtension::reset() -{ - for(TQMap<TQString, FILE*>::ConstIterator it = fileCache.begin(); it != fileCache.end(); it++) { - fclose(*it); -// remove( TQFile::encodeName(getPrecompiledLayoutFileName(*it)) ); - } - fileCache.clear(); + return true; } XKBExtension::~XKBExtension() @@ -94,106 +80,38 @@ XKBExtension::~XKBExtension() deletePrecompiledLayouts();*/ } -bool XKBExtension::setXkbOptions(const TQString& options, bool resetOld) +bool XKBExtension::setXkbOptions(const XkbOptions options) { - if (options.isEmpty()) - return true; - - TQString exe = TDEGlobal::dirs()->findExe("setxkbmap"); - if (exe.isEmpty()) - return false; - - TDEProcess p; - p << exe; - if( resetOld ) - p << "-option"; - p << "-option" << options; - - p.start(TDEProcess::Block); + TQString exe = TDEGlobal::dirs()->findExe("setxkbmap"); + if (exe.isEmpty()) + return false; - return p.normalExit() && (p.exitStatus() == 0); -} + TDEProcess p; + p << exe; -bool XKBExtension::setLayout(const TQString& model, - const TQString& layout, const TQString& variant, - const TQString& includeGroup, bool useCompiledLayouts) -{ - if( useCompiledLayouts == false ) { - return setLayoutInternal( model, layout, variant, includeGroup ); - } + p << "-layout"; + p << options.layouts; - const TQString layoutKey = getLayoutKey(layout, variant); + p << "-variant"; + p << options.variants; - bool res; - if( fileCache.contains(layoutKey) ) { - res = setCompiledLayout( layoutKey ); - kdDebug() << "[kxkb-extension] setCompiledLayout " << layoutKey << ": " << res << endl; - - if( res ) - return res; + if (!options.model.isEmpty()) { + p << "-model"; + p << options.model; } -// else { - res = setLayoutInternal( model, layout, variant, includeGroup ); - kdDebug() << "[kxkb-extension] setRawLayout " << layoutKey << ": " << res << endl; - if( res ) - compileCurrentLayout( layoutKey ); - -// } - return res; -} -// private -bool XKBExtension::setLayoutInternal(const TQString& model, - const TQString& layout, const TQString& variant, - const TQString& includeGroup) -{ - if ( layout.isEmpty() ) - return false; - - TQString exe = TDEGlobal::dirs()->findExe("setxkbmap"); - if( exe.isEmpty() ) { - kdError() << "[kxkb-extension] Can't find setxkbmap" << endl; - return false; + if (options.resetOld) { + p << "-option"; + } + if (!options.options.isEmpty()) { + p << "-option" << options.options; } - TQString fullLayout = layout; - TQString fullVariant = variant; - if( includeGroup.isEmpty() == false ) { - fullLayout = includeGroup; - fullLayout += ","; - fullLayout += layout; - -// fullVariant = baseVar; - fullVariant = ","; - fullVariant += variant; - } - - TDEProcess p; - p << exe; -// p << "-rules" << rule; - if( model.isEmpty() == false ) - p << "-model" << model; - p << "-layout" << fullLayout; - if( !fullVariant.isNull() && !fullVariant.isEmpty() ) - p << "-variant" << fullVariant; - - p.start(TDEProcess::Block); - - // reload system-wide hotkey-setup keycode -> keysym maps - TQString modmapFileName = TDEGlobal::dirs()->findResource( "data", "kxkb/system.xmodmap" ); - if ( TQFile::exists( modmapFileName ) ) { - TDEProcess pXmodmap; - pXmodmap << "xmodmap" << modmapFileName; - pXmodmap.start(TDEProcess::Block); - } + kdDebug() << "[kxkb-extension] Command: " << p.args() << endl; - if ( TQFile::exists( TQDir::home().path() + "/.Xmodmap" ) ) { - TDEProcess pXmodmapHome; - pXmodmapHome << "xmodmap" << TQDir::home().path() + "/.Xmodmap"; - pXmodmapHome.start(TDEProcess::Block); - } + p.start(TDEProcess::Block); - return p.normalExit() && (p.exitStatus() == 0); + return p.normalExit() && (p.exitStatus() == 0); } bool XKBExtension::setGroup(unsigned int group) @@ -209,130 +127,13 @@ unsigned int XKBExtension::getGroup() const return xkbState.group; } -/** - * @brief Gets the current layout in its binary compiled form - * and write it to the file specified by 'fileName' - * @param[in] fileName file to store compiled layout to - * @return true if no problem, false otherwise - */ -bool XKBExtension::compileCurrentLayout(const TQString &layoutKey) -{ - XkbFileInfo result; - memset(&result, 0, sizeof(result)); - result.type = XkmKeymapFile; - XkbReadFromServer(m_dpy, XkbAllMapComponentsMask, XkbAllMapComponentsMask, &result); - - const TQString fileName = getPrecompiledLayoutFilename(layoutKey); - - kdDebug() << "[kxkb-extension] compiling layout " << this << " cache size: " << fileCache.count() << endl; - if( fileCache.contains(layoutKey) ) { - kdDebug() << "[kxkb-extension] trashing old compiled layout for " << fileName << endl; - if( fileCache[ layoutKey ] != NULL ) - fclose( fileCache[ layoutKey ] ); // recompiling - trash the old file - fileCache.remove(fileName); - } - - FILE *output = fopen(TQFile::encodeName(fileName), "w"); - - if ( output == NULL ) - { - kdWarning() << "[kxkb-extension] Could not open " << fileName << " to precompile: " << strerror(errno) << endl; - XkbFreeKeyboard(result.xkb, XkbAllControlsMask, True); - return false; +/** 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); } - - if( !XkbWriteXKMFile(output, &result) ) { - kdWarning() << "[kxkb-extension] Could not write compiled layout to " << fileName << endl; - fclose(output); - return false; - } - - fclose(output); // TODO: can we change mode w/out reopening? - FILE *input = fopen(TQFile::encodeName(fileName), "r"); - fileCache[ layoutKey ] = input; - - XkbFreeKeyboard(result.xkb, XkbAllControlsMask, True); - return true; } -/** - * @brief takes layout from its compiled binary snapshot in file - * and sets it as current - * TODO: cache layout in memory rather than in file - */ -bool XKBExtension::setCompiledLayout(const TQString &layoutKey) -{ - FILE *input = NULL; - - if( fileCache.contains(layoutKey) ) { - input = fileCache[ layoutKey ]; - } - - if( input == NULL ) { - kdWarning() << "[kxkb-extension] setCompiledLayout trying to reopen xkb file" << endl; // should never happen - const TQString fileName = getPrecompiledLayoutFilename(layoutKey); - input = fopen(TQFile::encodeName(fileName), "r"); - - // FILE *input = fopen(TQFile::encodeName(fileName), "r"); - if ( input == NULL ) { - kdDebug() << "[kxkb-extension] Unable to open " << fileName << ": " << strerror(errno) << endl; - fileCache.remove(layoutKey); - return false; - } - } - else { - rewind(input); - } - - XkbFileInfo result; - memset(&result, 0, sizeof(result)); - if ((result.xkb = XkbAllocKeyboard())==NULL) { - kdWarning() << "[kxkb-extension] Unable to allocate memory for keyboard description" << endl; -// fclose(input); -// fileCache.remove(layoutKey); - return false; - } - - unsigned retVal = XkmReadFile(input, 0, XkmKeymapLegal, &result); - if (retVal == XkmKeymapLegal) - { - // this means reading the Xkm didn't manage to read any section - kdWarning() << "[kxkb-extension] Unable to load map from file" << endl; - XkbFreeKeyboard(result.xkb, XkbAllControlsMask, True); - fclose(input); - fileCache.remove(layoutKey); - return false; - } - - // fclose(input); // don't close - goes in cache - - if (XkbChangeKbdDisplay(m_dpy, &result) == Success) - { - if (!XkbWriteToServer(&result)) - { - kdWarning() << "[kxkb-extension] Unable to write the keyboard layout to X display" << endl; - XkbFreeKeyboard(result.xkb, XkbAllControlsMask, True); - return false; - } - } - else - { - kdWarning() << "[kxkb-extension] Unable prepare the keyboard layout for X display" << endl; - } - - XkbFreeKeyboard(result.xkb, XkbAllControlsMask, True); - return true; -} - - -// Deletes the precompiled layouts stored in temporary files -// void XKBExtension::deletePrecompiledLayouts() -// { -// TQMapConstIterator<LayoutUnit, TQString> it, end; -// end = m_compiledLayoutFileNames.end(); -// for (it = m_compiledLayoutFileNames.begin(); it != end; ++it) -// { -// unlink(TQFile::encodeName(it.data())); -// } -// m_compiledLayoutFileNames.clear(); -// } +#include "extension.moc"
\ No newline at end of file |