summaryrefslogtreecommitdiffstats
path: root/kxkb/extension.cpp
diff options
context:
space:
mode:
authorMavridis Philippe <mavridisf@gmail.com>2023-01-06 15:30:57 +0200
committerMavridis Philippe <mavridisf@gmail.com>2023-03-24 15:28:11 +0200
commita67db2d4847d798c01d4fd7584c5bb9297e109e3 (patch)
tree6cb5bb70f6201fa62dec021b92e838d32a6036ec /kxkb/extension.cpp
parentb50ab13974adf6f16d72f172f0cf768a44c161da (diff)
downloadtdebase-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.cpp263
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