not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kcontrol / kxkb / xklavier_adaptor.cpp
blob1a22e297be469624f2fcf36810fc1f4c44ff7bfc
1 /*
2 * Copyright (C) 2007 Andriy Rysin (rysin@kde.org)
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <locale.h>
21 #include <QTextDocument> // for Qt::escape
23 #include <kglobal.h>
24 #include <klocale.h>
25 #include <kdebug.h>
27 #include <libxklavier/xklavier.h>
29 #include "rules.h"
30 #include "kxkbconfig.h"
31 #include "xklavier_adaptor.h"
34 #define KDE_TRANSLATE 1
35 #define VERBOSE 0
37 class XKlavierAdaptorPriv {
38 public:
39 QHash<QString, QString> m_models;
40 QHash<QString, QString> m_layouts;
41 QHash<QString, QList<XkbVariant>*> m_variants;
42 QHash<QString, XkbOption> m_options;
43 QHash<QString, XkbOptionGroup> m_optionGroups;
45 static XklConfigRegistry *config;
47 QString currLayout;
48 XkbOptionGroup* currGroup;
49 XklEngine *engine;
52 XklConfigRegistry *XKlavierAdaptorPriv::config;
56 XKlavierAdaptor::XKlavierAdaptor(Display* dpy)
58 priv = new XKlavierAdaptorPriv();
60 g_type_init();
62 priv->engine = xkl_engine_get_instance(dpy);
63 if (priv->engine == NULL) {
64 kError() << "XKlavier engine cannot be initialized!" << endl;
65 return; // throw
68 #if KDE_TRANSLATE == 1
69 // If we cannot get XKlavier's own i18n to work,
70 // we have to manually translate strings it reports using its catalog.
71 // This catalog has to be in the locale paths which KDE will search.
72 KGlobal::locale()->insertCatalog("xkeyboard-config");
73 // KDE's i18n expects messages to be well-formed XML,
74 // so use Qt::escape() to replace < with &lt; etc.
75 // Actually we couldn't have done this just like that,
76 // as then an escaped message would not be found in the catalog;
77 // but, by a lucky fiat, xkeyboard-config too wants its messages as
78 // well-formed XML, so they come escaped exactly like this.
79 #define I18N_KDE(x) i18n(Qt::escape(QString::fromUtf8(x)).toUtf8())
80 #endif
83 QHash<QString, QString> XKlavierAdaptor::getModels() { return priv->m_models; }
84 QHash<QString, QString> XKlavierAdaptor::getLayouts() { return priv->m_layouts; }
85 QHash<QString, XkbOption> XKlavierAdaptor::getOptions() { return priv->m_options; }
86 QHash<QString, XkbOptionGroup> XKlavierAdaptor::getOptionGroups() { return priv->m_optionGroups; }
87 QHash<QString, QList<XkbVariant>*> XKlavierAdaptor::getVariants() { return priv->m_variants; }
91 static void processModel(XklConfigRegistry*, const XklConfigItem* configItem, gpointer userData)
93 QString model = QString::fromUtf8(configItem->name);
94 #if KDE_TRANSLATE == 1
95 QString desc = I18N_KDE(configItem->description);
96 #else
97 QString desc = QString::fromUtf8(configItem->description);
98 #endif
100 #if VERBOSE == 1
101 kDebug() << "model: " << model << " - " << desc;
102 #endif
104 ((XKlavierAdaptorPriv*)userData)->m_models.insert(model, desc);
108 static void processVariants(XklConfigRegistry*, const XklConfigItem* configItem, gpointer userData)
110 XkbVariant variant;
111 variant.name = QString::fromUtf8(configItem->name);
112 #if KDE_TRANSLATE == 1
113 variant.description = I18N_KDE(configItem->description);
114 #else
115 variant.description = QString::fromUtf8(configItem->description);
116 #endif
117 QString layout = ((XKlavierAdaptorPriv*)userData)->currLayout;
119 #if VERBOSE == 1
120 kDebug() << "\tvariant: " << variant.name << "-" << variant.description << " (parent: " << layout << ")";
121 #endif
123 QList<XkbVariant>* vars = ((XKlavierAdaptorPriv*)userData)->m_variants[layout];
124 vars->append(variant);
128 static void processLayout(XklConfigRegistry*, const XklConfigItem* configItem, gpointer userData)
130 QString layout = QString::fromUtf8(configItem->name);
131 #if KDE_TRANSLATE == 1
132 QString desc = I18N_KDE(configItem->description);
133 #else
134 QString desc = QString::fromUtf8(configItem->description);
135 #endif
137 #if VERBOSE == 1
138 kDebug() << "layout: " << layout << " - " << desc;
139 #endif
140 ((XKlavierAdaptorPriv*)userData)->m_layouts.insert(layout, desc);
141 ((XKlavierAdaptorPriv*)userData)->m_variants.insert(layout, new QList<XkbVariant>());
143 ((XKlavierAdaptorPriv*)userData)->currLayout = layout;
144 xkl_config_registry_foreach_layout_variant(XKlavierAdaptorPriv::config,
145 configItem->name, processVariants, userData);
149 static void processOptions(XklConfigRegistry*, const XklConfigItem* configItem, gpointer userData)
151 XkbOption option;
153 option.name = QString::fromUtf8(configItem->name);
154 #if KDE_TRANSLATE == 1
155 option.description = I18N_KDE(configItem->description);
156 #else
157 option.description = QString::fromUtf8(configItem->description);
158 #endif
159 option.group = ((XKlavierAdaptorPriv*)userData)->currGroup;
161 #if VERBOSE == 1
162 kDebug() << "\toptions: " << option.name;
163 #endif
165 ((XKlavierAdaptorPriv*)userData)->m_options.insert(option.name, option);
169 static void processOptionGroup(XklConfigRegistry*, const XklConfigItem* configItem, void *userData)
171 XkbOptionGroup group;
172 group.name = QString::fromUtf8(configItem->name);
173 #if KDE_TRANSLATE == 1
174 group.description = I18N_KDE(configItem->description);
175 #else
176 group.description = QString::fromUtf8(configItem->description);
177 #endif
178 group.exclusive = ! GPOINTER_TO_INT (g_object_get_data (G_OBJECT (configItem),
179 XCI_PROP_ALLOW_MULTIPLE_SELECTION));
181 #if VERBOSE == 1
182 kDebug() << "group: " << group.name << " - " << group.description;
183 #endif
185 ((XKlavierAdaptorPriv*)userData)->m_optionGroups.insert(group.name, group);
187 ((XKlavierAdaptorPriv*)userData)->currGroup =
188 &((XKlavierAdaptorPriv*)userData)->m_optionGroups[group.name];
189 xkl_config_registry_foreach_option(XKlavierAdaptorPriv::config,
190 configItem->name, processOptions, userData);
194 static const int LOCALE_CATEGORY = LC_ALL;
196 void XKlavierAdaptor::loadXkbConfig(bool layoutsOnly)
198 if( priv->engine == NULL )
199 return;
201 const char* currLocale = setlocale(LOCALE_CATEGORY, NULL);
203 QString locale = KGlobal::locale()->language();
204 if( locale.indexOf('_') == -1 ) { // TODO: do we have to do this?
205 QString country = KGlobal::locale()->country();
206 if( ! country.isEmpty() ) {
207 locale += "_";
208 locale += country.toUpper();
211 // locale = "uk_UA"; // testing
212 // locale = "en_US";
213 locale += ".UTF-8";
214 kDebug() << "Setting LC_ALL for libxklavier: " << locale;
216 const char* newLocale = setlocale(LOCALE_CATEGORY, locale.toLatin1());
217 if( newLocale == NULL ) {
218 kDebug() << "Setting locale " << locale << " failed - will use 'C' locale";
219 setlocale(LC_ALL, "C");
222 kDebug() << "Xklavier initialized";
223 priv->config = xkl_config_registry_get_instance(priv->engine);
225 xkl_config_registry_load(priv->config);
227 void *userData = priv;
229 // xkl_config_registry_set_custom_charset(priv->config, "UTF-8");
231 xkl_config_registry_foreach_layout(priv->config, processLayout, userData);
233 if( ! layoutsOnly ) {
234 xkl_config_registry_foreach_model(priv->config, processModel, userData);
235 xkl_config_registry_foreach_option_group(priv->config, processOptionGroup, userData);
238 kDebug() << priv->m_layouts.count() << "total layouts" << priv->m_models.count() << "models";
240 setlocale(LOCALE_CATEGORY, currLocale);
242 g_object_unref(priv->config);
245 XKlavierAdaptor::~XKlavierAdaptor()
247 g_object_unref(priv->engine);
248 // delete priv;
249 // kDebug() << "Finalizer";
252 XkbConfig
253 XKlavierAdaptor::getGroupNames()
255 XkbConfig xkbConfig;
257 // kDebug() << "retrieving active layout from server...";
258 XklConfigRec configRec;
259 xkl_config_rec_get_from_server(&configRec, priv->engine);
261 for(int ii=0; configRec.layouts[ii] != NULL && ii < GROUP_LIMIT; ii++) {
262 LayoutUnit lu;
263 lu.layout = configRec.layouts[ii];
264 lu.variant = configRec.variants[ii];
265 xkbConfig.layouts << lu;
266 kDebug() << " layout nm:" << lu.layout << "variant:" << lu.variant;
269 for(int ii=0; configRec.options[ii] != NULL && ii < 15; ii++) {
270 xkbConfig.options << configRec.options[ii];
271 kDebug() << " option:" << configRec.options[ii];
274 // const char **gn = xkl_engine_get_groups_names(priv->engine);
275 // int gt = xkl_engine_get_num_groups(priv->engine);
276 // int i;
277 // for (i = 0; i < gt; i++)
278 // kDebug() << "group:" << gn[i];
280 return xkbConfig;
283 static XKlavierAdaptor* instance = NULL;
285 XKlavierAdaptor*
286 XKlavierAdaptor::getInstance(Display* dpy)
288 if( instance == NULL ) {
289 instance = new XKlavierAdaptor(dpy);
291 return instance;
295 XKlavierAdaptor::startListening()
297 return xkl_engine_start_listen(priv->engine, XKLL_TRACK_KEYBOARD_STATE);
301 XKlavierAdaptor::stopListening()
303 return xkl_engine_start_listen(priv->engine, XKLL_TRACK_KEYBOARD_STATE);
306 int
307 XKlavierAdaptor::filterEvents(XEvent* ev)
309 return xkl_engine_filter_events(priv->engine, ev);