summaryrefslogtreecommitdiffstats
path: root/kkbswitch
diff options
context:
space:
mode:
authorSlávek Banko <slavek.banko@axis.cz>2013-08-18 15:43:45 +0200
committerSlávek Banko <slavek.banko@axis.cz>2013-08-18 15:43:45 +0200
commitae0c828ac29043e7adc56a78fc18d816b32c12b4 (patch)
tree51cc9b30f40faa951fc029f72c5f5b5e573e863d /kkbswitch
downloadkkbswitch-ae0c828ac29043e7adc56a78fc18d816b32c12b4.tar.gz
kkbswitch-ae0c828ac29043e7adc56a78fc18d816b32c12b4.zip
Initial import of kkbswitch 1.4.3
Diffstat (limited to 'kkbswitch')
-rw-r--r--kkbswitch/Makefile.am29
-rw-r--r--kkbswitch/Makefile.am.kdeinit31
-rw-r--r--kkbswitch/boldlistboxitem.cpp39
-rw-r--r--kkbswitch/boldlistboxitem.h40
-rw-r--r--kkbswitch/boldmenuitem.cpp68
-rw-r--r--kkbswitch/boldmenuitem.h52
-rw-r--r--kkbswitch/group_names44
-rw-r--r--kkbswitch/kbconfig.cpp340
-rw-r--r--kkbswitch/kbconfig.h110
-rw-r--r--kkbswitch/kbconfigdlg.cpp408
-rw-r--r--kkbswitch/kbconfigdlg.h84
-rw-r--r--kkbswitch/kbgroup.cpp26
-rw-r--r--kkbswitch/kbgroup.h48
-rw-r--r--kkbswitch/kbpickicondlg.cpp203
-rw-r--r--kkbswitch/kbpickicondlg.h61
-rw-r--r--kkbswitch/kbswitchapp.cpp379
-rw-r--r--kkbswitch/kbswitchapp.h131
-rw-r--r--kkbswitch/kbswitchintf.cpp51
-rw-r--r--kkbswitch/kbswitchintf.h54
-rw-r--r--kkbswitch/kbswitchintf.skel1
-rw-r--r--kkbswitch/kbswitchintf_skel.cpp74
-rw-r--r--kkbswitch/kbswitchtrayicon.cpp200
-rw-r--r--kkbswitch/kbswitchtrayicon.h72
-rw-r--r--kkbswitch/kkbswitch.desktop19
-rw-r--r--kkbswitch/main.cpp66
-rw-r--r--kkbswitch/pathlistboxitem.cpp28
-rw-r--r--kkbswitch/pathlistboxitem.h36
-rw-r--r--kkbswitch/ru_ua427
-rw-r--r--kkbswitch/singlewindowwatcher.cpp73
-rw-r--r--kkbswitch/singlewindowwatcher.h53
-rw-r--r--kkbswitch/windowclasswatcher.cpp106
-rw-r--r--kkbswitch/windowclasswatcher.h59
-rw-r--r--kkbswitch/windowwatcher.cpp37
-rw-r--r--kkbswitch/windowwatcher.h53
-rw-r--r--kkbswitch/xkeyboard.cpp246
-rw-r--r--kkbswitch/xkeyboard.h86
36 files changed, 3834 insertions, 0 deletions
diff --git a/kkbswitch/Makefile.am b/kkbswitch/Makefile.am
new file mode 100644
index 0000000..e3e3779
--- /dev/null
+++ b/kkbswitch/Makefile.am
@@ -0,0 +1,29 @@
+
+METASOURCES = AUTO
+
+bin_PROGRAMS = kkbswitch
+kkbswitch_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kkbswitch_SOURCES = boldlistboxitem.cpp boldmenuitem.cpp kbconfig.cpp kbconfigdlg.cpp kbgroup.cpp kbpickicondlg.cpp kbswitchapp.cpp kbswitchintf.cpp kbswitchtrayicon.cpp main.cpp pathlistboxitem.cpp xkeyboard.cpp kbswitchintf.skel boldlistboxitem.h boldmenuitem.h kbconfigdlg.h kbconfig.h kbgroup.h kbpickicondlg.h kbswitchapp.h kbswitchintf.h kbswitchtrayicon.h pathlistboxitem.h xkeyboard.h windowwatcher.cpp singlewindowwatcher.cpp windowclasswatcher.cpp
+
+INCLUDES = $(all_includes)
+
+kkbswitch_LDADD = $(LIB_KIO) $(LIB_KDEUI)
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kkbswitch.pot
+
+noinst_HEADERS = windowwatcher.h singlewindowwatcher.h windowclasswatcher.h
+
+kkbswitchdatadir = $(kde_datadir)/kkbswitch
+kkbswitchdata_DATA = group_names
+
+applnkUtilities_DATA = kkbswitch.desktop
+applnkUtilitiesdir = $(kde_appsdir)/Utilities
+
+if ENABLE_RU_UA_LAYOUT
+xkbsymbolsdir = $(x_libraries)/X11/xkb/symbols
+xkbsymbols_DATA = ru_ua
+endif
+
+autostartdir = $(prefix)/share/autostart
+autostart_DATA = kkbswitch.desktop
diff --git a/kkbswitch/Makefile.am.kdeinit b/kkbswitch/Makefile.am.kdeinit
new file mode 100644
index 0000000..75ab6b8
--- /dev/null
+++ b/kkbswitch/Makefile.am.kdeinit
@@ -0,0 +1,31 @@
+
+METASOURCES = AUTO
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kkbswitch.la
+kkbswitch_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -module -avoid-version
+kkbswitch_la_SOURCES = boldlistboxitem.cpp boldmenuitem.cpp kbconfig.cpp kbconfigdlg.cpp kbgroup.cpp kbpickicondlg.cpp kbswitchapp.cpp kbswitchintf.cpp kbswitchtrayicon.cpp main.cpp pathlistboxitem.cpp xkeyboard.cpp kbswitchintf.skel boldlistboxitem.h boldmenuitem.h kbconfigdlg.h kbconfig.h kbgroup.h kbpickicondlg.h kbswitchapp.h kbswitchintf.h kbswitchtrayicon.h pathlistboxitem.h xkeyboard.h windowwatcher.cpp singlewindowwatcher.cpp windowclasswatcher.cpp
+
+INCLUDES = $(all_includes)
+
+kkbswitch_la_LIBADD = $(LIB_KIO) $(LIB_KDEUI)
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kkbswitch.pot
+
+noinst_HEADERS = windowwatcher.h singlewindowwatcher.h windowclasswatcher.h
+
+kkbswitchdatadir = $(kde_datadir)/kkbswitch
+kkbswitchdata_DATA = group_names
+
+applnkUtilities_DATA = kkbswitch.desktop
+applnkUtilitiesdir = $(kde_appsdir)/Utilities
+
+if ENABLE_RU_UA_LAYOUT
+xkbsymbolsdir = $(x_libraries)/X11/xkb/symbols
+xkbsymbols_DATA = ru_ua
+endif
+
+autostartdir = $(prefix)/share/autostart
+autostart_DATA = kkbswitch.desktop
diff --git a/kkbswitch/boldlistboxitem.cpp b/kkbswitch/boldlistboxitem.cpp
new file mode 100644
index 0000000..a136f0c
--- /dev/null
+++ b/kkbswitch/boldlistboxitem.cpp
@@ -0,0 +1,39 @@
+/***************************************************************************
+ boldlistboxitem.cpp - description
+ -------------------
+ begin : ??? ??? 12 2003
+ copyright : (C) 2003 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "boldlistboxitem.h"
+#include <qpainter.h>
+
+BoldListBoxItem::BoldListBoxItem(QListBox *listbox, const QPixmap &pix,
+ const QString &text, bool bold)
+ : QListBoxPixmap(listbox, pix, text), m_bold(bold)
+{
+}
+
+BoldListBoxItem::~BoldListBoxItem()
+{
+}
+
+void BoldListBoxItem::paint(QPainter *painter)
+{
+ if (m_bold) {
+ QFont font = painter->font();
+ font.setBold(true);
+ painter->setFont(font);
+ }
+ QListBoxPixmap::paint(painter);
+}
diff --git a/kkbswitch/boldlistboxitem.h b/kkbswitch/boldlistboxitem.h
new file mode 100644
index 0000000..49ca269
--- /dev/null
+++ b/kkbswitch/boldlistboxitem.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ boldlistboxitem.h - description
+ -------------------
+ begin : Sun Oct 12 2003
+ copyright : (C) 2003 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BOLDLISTBOXITEM_H
+#define BOLDLISTBOXITEM_H
+
+#include <qlistbox.h>
+
+/**Listbox item that can optionally display its text in bold
+ *@author Leonid Zeitlin
+ */
+
+class BoldListBoxItem : public QListBoxPixmap {
+private:
+ bool m_bold;
+protected:
+ virtual void paint (QPainter *painter);
+public:
+ BoldListBoxItem(QListBox *listbox, const QPixmap &pix, const QString &text,
+ bool bold = false);
+ ~BoldListBoxItem();
+ bool bold() { return m_bold; }
+ void setBold(bool bold) { m_bold = bold; }
+};
+
+#endif
diff --git a/kkbswitch/boldmenuitem.cpp b/kkbswitch/boldmenuitem.cpp
new file mode 100644
index 0000000..1c12656
--- /dev/null
+++ b/kkbswitch/boldmenuitem.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+ boldmenuitem.cpp - description
+ -------------------
+ begin : Sat Sep 1 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "boldmenuitem.h"
+#include <qfont.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qstyle.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <kdeversion.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kapplication.h>
+#else
+ #include <kapp.h>
+#endif
+
+
+BoldMenuItem::BoldMenuItem(const QString &text, const QColor &active_text_color,
+ bool bold)
+ : m_text(text), m_active_text_color(active_text_color), m_bold(bold)
+{
+}
+
+BoldMenuItem::~BoldMenuItem(){
+}
+
+void BoldMenuItem::paint(QPainter* painter, const QColorGroup& /*cg*/,
+ bool act, bool /*enabled*/, int x, int y, int w, int h)
+{
+ QFont font = painter->font();
+ if (font.bold() != m_bold) {
+ font.setBold(m_bold);
+ painter->setFont(font);
+ }
+ //if (act) painter->setPen(KGlobalSettings::highlightedTextColor());
+ //if (act) painter->setPen(cg.highlightedText());
+ if (act) painter->setPen(m_active_text_color);
+ kdDebug() << "bg color = " << painter->brush().color().rgb() << endl;
+
+ painter->drawText(x, y, w, h, AlignLeft | AlignVCenter | ShowPrefix | DontClip,
+ m_text);
+ //KApplication::style().drawItem(painter, QRect(x, y, w, h), AlignLeft | AlignVCenter | ShowPrefix | DontClip,
+ // cg, enabled, 0, m_text);
+}
+
+
+void BoldMenuItem::setFont(const QFont& font)
+{
+ m_size = QFontMetrics(font).size(AlignLeft | AlignVCenter | ShowPrefix | DontClip,
+ m_text);
+ QCustomMenuItem::setFont(font);
+}
+
diff --git a/kkbswitch/boldmenuitem.h b/kkbswitch/boldmenuitem.h
new file mode 100644
index 0000000..99ed2b9
--- /dev/null
+++ b/kkbswitch/boldmenuitem.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ boldmenuitem.h - description
+ -------------------
+ begin : Sat Sep 1 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BOLDMENUITEM_H
+#define BOLDMENUITEM_H
+
+#include <qmenudata.h>
+
+/**A custom menu item that can display its text in bold
+ *@author Leonid Zeitlin
+ * 02.09.2001: somehow I cannot make it work. The item looks ok when not
+ * selected, but appears empty when selected. I have a suspicion that this
+ * is a problem with some KDE styles (B3 in particular), the style doesn't
+ * paint custom menu items correctly. With some other styles, such as Qt built-in
+ * Windows style, everything works correctly. I suspend the work on this for the
+ * time being...
+ */
+
+class BoldMenuItem : public QCustomMenuItem {
+private:
+ QString m_text;
+ QColor m_active_text_color;
+ bool m_bold;
+ QSize m_size;
+public:
+ BoldMenuItem(const QString &text, const QColor &active_text_color, bool bold = false);
+ ~BoldMenuItem();
+ QString& text() { return m_text; };
+ void setText(const QString& value) { m_text = value; };
+ bool bold() { return m_bold; };
+ void setBold(bool value) { m_bold = value; };
+ virtual void paint(QPainter* painter, const QColorGroup& /*cg*/,
+ bool act, bool /*enabled*/, int x, int y, int w, int h);
+ virtual void setFont(const QFont& font);
+ virtual QSize sizeHint() { return m_size; };
+};
+
+#endif
diff --git a/kkbswitch/group_names b/kkbswitch/group_names
new file mode 100644
index 0000000..2c3d40d
--- /dev/null
+++ b/kkbswitch/group_names
@@ -0,0 +1,44 @@
+[Mapping]
+US/ASCII=us
+Belgian=be
+Bulgarian=bg
+Canadian=ca
+Czech=cz
+Danish=dk
+Finnish=fi
+French=fr
+Georgian=ge
+German=de
+Great Britain=gb
+Greek=gr
+Hungarian=hu
+Icelandic=is
+ISO8859-7=gr
+Israelian=il
+Italian=it
+Latvian=lv
+Lithuanian=lt
+Macedonian=mk
+Norwegian=no
+Polish=pl
+Portugese=pt
+Russian=ru
+Slovak=sk
+Spanish=es
+Swedish=se
+Swiss French=ch
+Swiss German=ch
+Thai=th
+Ukrainian=ua
+Vietnamese=vn
+
+[Languages]
+US/ASCII=en
+Canadian=en
+Great Britain=en
+Greek=el
+ISO8859-7=el
+Israelian=he
+Swiss French=fr
+Swiss German=de
+Ukrainian=uk
diff --git a/kkbswitch/kbconfig.cpp b/kkbswitch/kbconfig.cpp
new file mode 100644
index 0000000..b7c5cac
--- /dev/null
+++ b/kkbswitch/kbconfig.cpp
@@ -0,0 +1,340 @@
+/***************************************************************************
+ kbconfig.cpp - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <config.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kglobal.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kstandarddirs.h>
+ #include <kapplication.h>
+#else
+ #include <kstddirs.h>
+ #include <kapp.h>
+#endif
+#include <kglobalsettings.h>
+#include <kdebug.h>
+#include <kglobalaccel.h>
+
+#include <qnamespace.h>
+#include <qpainter.h>
+#include <qimage.h>
+
+#include "kbconfig.h"
+#include "xkeyboard.h"
+
+#ifdef HAVE_X11_EXTENSIONS_XKBRULES_H
+ #include <X11/extensions/XKBrules.h>
+#endif
+
+#define TOGGLE_MODE_ENTRY "toggle_mode"
+#define DEFAULT_GROUP_ENTRY "default_group"
+//#define PERWINDOW_GROUP_ENTRY "perwindow_group"
+#define ICON_TYPE_ENTRY "icon_type"
+#define AUTOSTART_ENTRY "autostart"
+#define USE_SHORTCUTS_ENTRY "use_shorcuts"
+#define GROUP_SCOPE_ENTRY "group_scope"
+
+KBConfig::KBConfig()
+{
+ m_toggle_mode = false;
+ m_groups.setAutoDelete(true);
+ m_default_groupno = 0;
+ //m_perwindow_group = false;
+ m_group_scope = SCOPE_GLOBAL;
+ m_autostart = true;
+ m_icon_style = ICON_CODE_AND_FLAG;
+ //m_keys = new KGlobalAccel(NULL);
+ m_keys = NULL;
+}
+
+KBConfig::~KBConfig()
+{
+ delete m_keys;
+}
+
+/** load the KBSwitch configration from the application KConfig object */
+void KBConfig::load(KConfig *config){
+ config->setGroup(OPTIONS_SECTION);
+ m_toggle_mode = config->readBoolEntry(TOGGLE_MODE_ENTRY);
+ m_default_groupno = config->readNumEntry(DEFAULT_GROUP_ENTRY);
+ //m_perwindow_group = config->readBoolEntry(PERWINDOW_GROUP_ENTRY);
+ m_group_scope = GroupScope(config->readNumEntry(GROUP_SCOPE_ENTRY, SCOPE_GLOBAL));
+ m_autostart = config->readBoolEntry(AUTOSTART_ENTRY, true);
+ m_icon_style = IconStyle(config->readNumEntry(ICON_TYPE_ENTRY, ICON_FLAG));
+ m_use_shortcuts = config->readBoolEntry(USE_SHORTCUTS_ENTRY, false);
+
+ XKeyboard *xkb = XKeyboard::self();
+ QStringList list;
+ xkb->getGroupNames(list);
+ unsigned int i = 0;
+ m_groups.clear();
+ m_groups.resize(xkb->getNumKbdGroups());
+ QString name;
+ for (QStringList::Iterator iter = list.begin(); iter != list.end(); iter++, i++) {
+ name = *iter;
+ if (name == QString::null) name = i18n("<Unnamed>");
+ m_groups.insert(i, new KBGroup(name));
+ }
+
+ QValueVector<QPixmap> pixlist;
+ QStringList iconpaths;
+ drawIcons(m_icon_style, &pixlist, &iconpaths);
+ for (i = 0; i < m_groups.count(); i++) {
+ m_groups[i]->setPixmap(pixlist[i]);
+ m_groups[i]->setIconPath(iconpaths[i]);
+ }
+
+ if (m_keys) delete m_keys;
+ m_keys = new KGlobalAccel(NULL);
+ for (int i = 0; i < groupCount(); i++) {
+ m_keys->insert(QString::fromLatin1("SetGroup %1").arg(i),
+ i18n("Activate %1 keyboard layout").arg(m_groups[i]->getName()),
+ QString::null, Qt::ALT+Qt::CTRL+Qt::Key_1 + i, KKey::QtWIN+Qt::CTRL+Qt::Key_1 + i,
+ kapp, SLOT(slotGroupSelected(int)));
+ }
+ m_keys->readSettings(config);
+ checkKeysEnabled();
+}
+
+void KBConfig::save(KConfig *config)
+{
+ config->setGroup(OPTIONS_SECTION);
+ config->writeEntry(TOGGLE_MODE_ENTRY, m_toggle_mode);
+ config->writeEntry(DEFAULT_GROUP_ENTRY, m_default_groupno);
+ //config->writeEntry(PERWINDOW_GROUP_ENTRY, m_perwindow_group);
+ config->writeEntry(GROUP_SCOPE_ENTRY, m_group_scope);
+ config->writeEntry(ICON_TYPE_ENTRY, m_icon_style);
+ config->writeEntry(AUTOSTART_ENTRY, m_autostart);
+ config->writeEntry(USE_SHORTCUTS_ENTRY, m_use_shortcuts);
+ m_keys->writeSettings(config);
+}
+
+void KBConfig::drawIcons(IconStyle icon_style, QValueVector<QPixmap> *icons,
+ QStringList *iconpaths)
+{
+ QString path, countryCode, langCode;
+ QStringList layouts;
+
+ KGlobal::dirs()->addResourceDir("appdata", ".");
+ KConfig map("group_names", true, true, "appdata");
+ KConfig *config = kapp->config();
+ config->setGroup(ICONS_SECTION);
+ getXkbLayouts(layouts);
+
+ icons->clear();
+ icons->resize(m_groups.count());
+ iconpaths->clear();
+ for (unsigned int i = 0; i < m_groups.count(); i++) {
+ map.setGroup("Mapping");
+ countryCode = map.readEntry(m_groups[i]->getName());
+ // if the country code can't be guessed from group name, try XKB layout name
+ if (countryCode.isEmpty() && i < layouts.count()) countryCode = layouts[i];
+ map.setGroup("Languages");
+ langCode = map.readEntry(m_groups[i]->getName());
+ if (langCode.isEmpty()) langCode = countryCode;
+ QPixmap &pix = (*icons)[i];
+ pix.resize(0, 0);
+ path = QString::null;
+ if (icon_style == ICON_FLAG /*&& !countryCode.isEmpty()*/)
+ drawFlagPixmap(pix, path, countryCode, i, config);
+ else if (icon_style == ICON_CODE_AND_FLAG /*&& !countryCode.isEmpty()*/)
+ drawCodeAndFlagPixmap(pix, path, countryCode, langCode, i, config);
+ if (pix.isNull() && !langCode.isEmpty())
+ drawCodePixmap(pix, langCode);
+ if (pix.isNull()) drawDefaultPixmap(pix, i);
+ iconpaths->append(path);
+ }
+}
+
+/** No descriptions */
+/*void KBConfig::guessGroupPixmaps(){
+ KGlobal::dirs()->addResourceDir("appdata", ".");
+ KConfig map("group_names", true, true, "appdata");
+ QString path, countryCode, langCode;
+ QPixmap pix;
+
+ for (unsigned int i = 0; i < m_groups.count(); i++) {
+ if (m_groups[i]->getPixmap().isNull()) {
+ map.setGroup("Mapping");
+ countryCode = map.readEntry(m_groups[i]->getName());
+ map.setGroup("Languages");
+ langCode = map.readEntry(m_groups[i]->getName());
+ if (langCode.isEmpty()) langCode = countryCode;
+ pix.resize(0, 0);
+ if (m_icon_type == ICON_FLAG && !countryCode.isEmpty())
+ drawFlagPixmap(pix, countryCode);
+ else if (m_icon_type == ICON_CODE_AND_FLAG && !countryCode.isEmpty())
+ drawCodeAndFlagPixmap(pix, countryCode, langCode);
+ if (pix.isNull() && !langCode.isEmpty())
+ drawCodePixmap(pix, langCode);
+ if (!pix.isNull()) m_groups[i]->setPixmap(pix);
+ }
+ }
+}*/
+
+bool KBConfig::getGroupImage(QImage &img, QString &path, const QString &code,
+ int group, KConfig *config)
+{
+ bool ret = true;
+ bool need_to_scale = false;
+
+ path = config->readEntry(m_groups[group]->getName()/*entryForGroup(group)*/);
+ if (path.isEmpty() || !img.load(path)) {
+ if (code.isEmpty()) ret = false;
+ else {
+ path = locate("locale", QString("l10n/%1/flag.png").arg(code));
+ if (!path.isEmpty()) ret = img.load(path);
+ else {
+ // I am told in Red Hat 9 standard KDE flag pixmaps are missing.
+ // Workaround: we have to simulate them by rescaling GKB's pixmaps
+ path = QString("/usr/share/pixmaps/gkb/%1.png").arg(code);
+ ret = img.load(path) && !img.isNull();
+ need_to_scale = true;
+ }
+ }
+ }
+ if (ret) {
+ // if need_to_scale is not already set, set it if image is too wide
+ if (!need_to_scale) need_to_scale = img.width() > 24;
+ if (need_to_scale) img = img.smoothScale(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT);
+ }
+ return ret;
+}
+
+void KBConfig::drawFlagPixmap(QPixmap &pix, QString &path, const QString &code,
+ int group, KConfig *config)
+{
+ QImage img;
+ if (getGroupImage(img, path, code, group, config))
+ pix.convertFromImage(img);
+}
+
+void KBConfig::drawCodePixmap(QPixmap &pix, const QString &code)
+{
+ pix.resize(19, 16);
+
+ QPainter painter(&pix);
+ QFont font("helvetica", 9, QFont::Bold);
+ font.setPixelSize(10);
+ painter.setFont(font);
+ painter.setPen(KGlobalSettings::highlightedTextColor());
+
+ pix.fill(KGlobalSettings::highlightColor());
+ painter.drawText(1, 0, pix.width(), pix.height(),
+ Qt::AlignHCenter | Qt::AlignVCenter, code.upper());
+
+ /*QSize size = painter.fontMetrics().size(0, code.upper());
+ kdDebug() << size.width() << " x " << size.height() << endl;*/
+}
+
+void KBConfig::drawCodeAndFlagPixmap(QPixmap &pix, QString &path,
+ const QString &countryCode, const QString &langCode, int group, KConfig *config)
+{
+ QImage img;
+ if (!getGroupImage(img, path, countryCode, group, config)) return; // could not find flag
+ if (img.depth() <= 8) img = img.convertDepth(32);
+
+ // the following code is taken from kdebase/kxkb/pixmap.cpp
+ for (int y = 0; y < img.height(); y++)
+ for(int x = 0; x < img.width(); x++) {
+ QRgb rgb = img.pixel(x, y);
+ img.setPixel(x, y, qRgb(qRed(rgb)*3/4, qGreen(rgb)*3/4, qBlue(rgb)*3/4));
+ }
+ pix.convertFromImage(img);
+
+ QPainter painter(&pix);
+ painter.setPen(Qt::black);
+ painter.setFont(QFont("helvetica", 10, QFont::Bold));
+ painter.drawText(1, 1, pix.width(), pix.height()-2, Qt::AlignCenter, langCode);
+ painter.setPen(Qt::white);
+ painter.drawText(0, 0, pix.width(), pix.height()-2, Qt::AlignCenter, langCode);
+}
+
+void KBConfig::drawDefaultPixmap(QPixmap &pix, int group)
+{
+ pix.resize(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT);
+ QPainter painter(&pix);
+ pix.fill();
+ painter.drawText(0, 0, pix.width(), pix.height(),
+ Qt::AlignHCenter | Qt::AlignVCenter, QString::number(group+1));
+}
+
+void KBConfig::checkKeysEnabled()
+{
+ m_keys->setEnabled(m_use_shortcuts);
+ m_keys->updateConnections();
+}
+
+
+/** No descriptions */
+/*void KBConfig::drawDefaultPixmaps(){
+ QPixmap pix(16, 16);
+ QPainter painter(&pix);
+
+ for (unsigned int i = 0; i < m_groups.count(); i++) {
+ if (m_groups[i]->getPixmap().isNull()) {
+ pix.fill();
+ painter.drawText(0, 0, pix.width(), pix.height(),
+ Qt::AlignHCenter | Qt::AlignVCenter, QString::number(i+1));
+ m_groups[i]->setPixmap(pix);
+ }
+ }
+}*/
+
+/** No descriptions */
+/*void KBConfig::loadConfiguredPixmaps(KConfig *config){
+ QString path;
+ QPixmap pix;
+ config->setGroup(ICONS_SECTION);
+ for (unsigned int i = 0; i < m_groups.count(); i++) {
+ path = config->readEntry(entryForGroup(i));
+ if (!path.isEmpty() && pix.load(path))
+ m_groups[i]->setPixmap(pix);
+ }
+}*/
+
+/** No descriptions */
+/*void KBConfig::notifyChanged(){
+ emit changed();
+}*/
+
+
+/*!
+ \fn KBConfig::getXkbLayouts(const QStringList &layouts)
+ */
+void KBConfig::getXkbLayouts(QStringList &layouts)
+{
+#if HAVE_X11_EXTENSIONS_XKBRULES_H && HAVE_LIBXKBFILE
+ XkbRF_VarDefsRec vardefs;
+ int i;
+
+ usleep(10000);
+ if (XkbRF_GetNamesProp(qt_xdisplay(), NULL, &vardefs)) {
+ layouts = QStringList::split(',', vardefs.layout, true);
+ for (QStringList::Iterator it = layouts.begin(); it != layouts.end(); ++it) {
+ i = 0;
+ while ((*it)[i] >= 'a' && (*it)[i] <= 'z') i++;
+ *it = (*it).left(i);
+ }
+ if (vardefs.layout) XFree(vardefs.layout);
+ if (vardefs.model) XFree(vardefs.model);
+ if (vardefs.variant) XFree(vardefs.variant);
+ if (vardefs.options) XFree(vardefs.options);
+ }
+#endif
+}
diff --git a/kkbswitch/kbconfig.h b/kkbswitch/kbconfig.h
new file mode 100644
index 0000000..7187263
--- /dev/null
+++ b/kkbswitch/kbconfig.h
@@ -0,0 +1,110 @@
+/***************************************************************************
+ kbconfig.h - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBCONFIG_H
+#define KBCONFIG_H
+
+#include "kbgroup.h"
+
+#include <qptrvector.h>
+#include <qvaluevector.h>
+#include <kconfig.h>
+
+#define ICONS_SECTION "Icons"
+#define OPTIONS_SECTION "Options"
+
+#define FLAG_ICON_WIDTH 21
+#define FLAG_ICON_HEIGHT 14
+
+class KGlobalAccel;
+
+typedef QPtrVector<KBGroup> KBGroupVector;
+
+/**The class that stores configuration information of KBSwitch
+ *@author Leonid Zeitlin
+ */
+
+class KBConfig {
+public:
+ enum IconStyle { ICON_FLAG, ICON_CODE, ICON_CODE_AND_FLAG };
+ enum GroupScope { SCOPE_GLOBAL, SCOPE_CLASS, SCOPE_WINDOW };
+private:
+ KBGroupVector m_groups;
+ bool m_toggle_mode;
+ int m_default_groupno;
+ //bool m_perwindow_group;
+ GroupScope m_group_scope;
+ bool m_autostart;
+ bool m_use_shortcuts;
+ IconStyle m_icon_style;
+ KGlobalAccel *m_keys;
+public:
+ KBConfig();
+ ~KBConfig();
+ int groupCount() { return m_groups.count(); };
+ KBGroup *getGroup(int groupno) { return m_groups[groupno]; };
+ bool toggle_mode() {return m_toggle_mode; };
+ /** No descriptions */
+ void set_toggle_mode(bool value) {m_toggle_mode = value; };
+ int default_groupno() { return m_default_groupno; };
+ void set_default_groupno(int value) { m_default_groupno = value; };
+ /*bool perwindow_group() { return m_perwindow_group; };
+ void set_perwindow_group(int value) { m_perwindow_group = value; };*/
+ GroupScope group_scope() { return m_group_scope; }
+ void set_group_scope(GroupScope value) { m_group_scope = value; }
+ bool autostart() { return m_autostart; }
+ void set_autostart(bool value) { m_autostart = value; }
+ IconStyle icon_style() { return m_icon_style; }
+ void set_icon_style(IconStyle value) { m_icon_style = value; }
+ bool use_shortcuts() { return m_use_shortcuts; }
+ void set_use_shortcuts(bool value) { m_use_shortcuts = value; }
+ KGlobalAccel *keys() { return m_keys; }
+ /** Load the KBSwitch configration from the application KConfig object */
+ void load(KConfig *config);
+ /** Save the KBSwitch configration to the application KConfig object */
+ void save(KConfig *config);
+ /** No descriptions */
+ /*void notifyChanged();*/
+ /*static QString entryForGroup(int i) {
+ return QString("Group%1").arg(i+1);
+ }*/
+ void drawIcons(IconStyle icon_style, QValueVector<QPixmap> *icons,
+ QStringList *iconpaths);
+ void checkKeysEnabled();
+ int getNextGroup(int groupno) {
+ return groupno >= groupCount() - 1 ? 0 : groupno + 1;
+ }
+private: // Private methods
+ /** No descriptions */
+ //void guessGroupPixmaps();
+ /** No descriptions */
+ //void drawDefaultPixmaps();
+ /** No descriptions */
+ //void loadConfiguredPixmaps(KConfig *config);
+ void drawFlagPixmap(QPixmap &pix, QString &path, const QString &code,
+ int group, KConfig *config);
+ void drawCodePixmap(QPixmap &pix, const QString &code);
+ void drawCodeAndFlagPixmap(QPixmap &pix, QString &path,
+ const QString &countryCode, const QString &langCode, int group,
+ KConfig *config);
+ void drawDefaultPixmap(QPixmap &pix, int group);
+ bool getGroupImage(QImage &img, QString &path, const QString &code, int group,
+ KConfig *config);
+ void getXkbLayouts(QStringList &layouts);
+};
+
+#endif
diff --git a/kkbswitch/kbconfigdlg.cpp b/kkbswitch/kbconfigdlg.cpp
new file mode 100644
index 0000000..0b599c1
--- /dev/null
+++ b/kkbswitch/kbconfigdlg.cpp
@@ -0,0 +1,408 @@
+/***************************************************************************
+ kbconfigdlg.cpp - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kbconfigdlg.h"
+#include "kbpickicondlg.h"
+#include "boldlistboxitem.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qwhatsthis.h>
+#include <qvbox.h>
+#include <qstyle.h>
+#include <qgroupbox.h>
+#include <qheader.h>
+#include <qobjectlist.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+
+#include <kdeversion.h>
+#include <klistbox.h>
+#include <klocale.h>
+#include <kdebug.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kapplication.h>
+#else
+ #include <kapp.h>
+#endif
+#include <klistview.h>
+#include <kkeydialog.h>
+#include <kconfig.h>
+
+/* This little subclass of KKeyChooser reimplements sizeHint() to
+ look a little smaller in our config dialog. The default size
+ is way too large IMHO and makes General page look oversized
+ */
+class SmallerKeyChooser : public KKeyChooser {
+private:
+ QSize m_size_hint;
+ void calcSizeHint();
+public:
+ SmallerKeyChooser(KGlobalAccel *accel, QWidget *parent) :
+ KKeyChooser(accel, parent) { calcSizeHint(); }
+ virtual QSize sizeHint() const { return m_size_hint; }
+};
+
+void SmallerKeyChooser::calcSizeHint()
+{
+ m_size_hint = KKeyChooser::sizeHint();
+
+ KListView *lv = NULL;
+ QGroupBox *gb = NULL;
+ const QObjectList *objects = children();
+ QObjectListIt iter(*objects);
+ QObject *obj;
+
+ while ( (obj = iter.current()) ) {
+ ++iter;
+ if (obj->inherits("KListView"))
+ lv = dynamic_cast<KListView*>(obj);
+ else if (obj->inherits("QGroupBox"))
+ gb = dynamic_cast<QGroupBox*>(obj);
+ }
+ if (!lv || !gb) return; // oops, should not happen
+
+ QListViewItem *item = lv->firstChild();
+ if (!item) return;
+
+ int height = item->height() * (1 + item->childCount()) + lv->header()->height() +
+ style().pixelMetric(QStyle::PM_ScrollBarExtent) + gb->sizeHint().height() +
+ layout()->spacing() * 2;
+ int width = lv->columnWidth(0) + lv->columnWidth(1);
+ m_size_hint = QSize(width, height);
+}
+
+static inline bool iconTypeShowsFlag(KBConfig::IconStyle icon_style)
+{
+ return icon_style == KBConfig::ICON_FLAG || icon_style == KBConfig::ICON_CODE_AND_FLAG;
+}
+
+KBConfigDlg::KBConfigDlg(KBConfig *kbconf, QWidget *parent, const char *name )
+ : KDialogBase(Tabbed, i18n("Configure")/*caption*/, Ok | Apply | Cancel | Help,
+ Ok, parent, name, true /*modal*/)
+{
+ m_kbconf = kbconf;
+ m_default_groupno = m_kbconf->default_groupno();
+
+ setHelp(QString("configure-kkbswitch"));
+ setButtonBoxOrientation(Horizontal);
+ setupGeneralPage();
+ setupShortcutsPage();
+
+ showConfig();
+ slotIconTypeSelected(m_kbconf->icon_style());
+}
+
+KBConfigDlg::~KBConfigDlg(){
+}
+
+void KBConfigDlg::setupGeneralPage()
+{
+ QFrame *page = addPage(i18n("&General")); //makeMainWidget();
+ QVBoxLayout *vlayout = new QVBoxLayout(page);
+ vlayout->setSpacing(2);
+
+ QLabel *lbl = new QLabel(i18n("Available &keyboard layouts:"), page);
+ vlayout->addWidget(lbl);
+
+ QHBoxLayout *groupsLayout = new QHBoxLayout(vlayout);
+ groupsLayout->setSpacing(2);
+
+ lbGroups = new KListBox(page);
+ QObject::connect(lbGroups, SIGNAL(selectionChanged()), this, SLOT(slotLayoutSelected()));
+ QObject::connect(lbGroups, SIGNAL(doubleClicked(QListBoxItem *)), this,
+ SLOT(slotListBoxExecuted(QListBoxItem *)));
+ groupsLayout->addWidget(lbGroups);
+ lbl->setBuddy(lbGroups);
+ QWhatsThis::add(lbGroups, i18n("This list box shows keyboard layouts available in your system.\n"
+ "Select a layout and click \"Change Icon...\" button to change the icon for a layout.\n"
+ "If you have configured a non-default icon, you can reset the icon to default with \"Use Default Icon\" button.\n"
+ "The layout shown is bold is the default layout. Use \"Set as default\" button "
+ "to set the default layout."));
+
+ QVBoxLayout *btnLayout = new QVBoxLayout(groupsLayout);
+ btnLayout->setSpacing(2);
+
+ btnChangeIcon = new QPushButton(i18n("Cha&nge Icon..."), page);
+ QObject::connect(btnChangeIcon, SIGNAL(clicked()), this, SLOT(slotPickIcon()));
+ btnLayout->addWidget(btnChangeIcon, 0, Qt::AlignTop);
+ QWhatsThis::add(btnChangeIcon, i18n("Click this button to change the icon for the "
+ "layout selected in the list box to the left."));
+
+ btnSetDefaultIcon = new QPushButton(i18n("Use &Default Icon"), page);
+ QObject::connect(btnSetDefaultIcon, SIGNAL(clicked()), this, SLOT(slotSetDefaultIcon()));
+ btnLayout->addWidget(btnSetDefaultIcon, 0, Qt::AlignTop);
+ QWhatsThis::add(btnSetDefaultIcon, i18n("Click this button to use default icon for the "
+ "layout selected in the list box to the left."));
+
+ btnSetDefaultGroup = new QPushButton(i18n("&Set as Default"), page);
+ QObject::connect(btnSetDefaultGroup, SIGNAL(clicked()), this, SLOT(slotSetDefaultGroup()));
+ btnLayout->addWidget(btnSetDefaultGroup, 0, Qt::AlignTop);
+ QWhatsThis::add(btnSetDefaultGroup, i18n("Cick this button to set the layout selected "
+ "in the list box to the left as the default"));
+
+ btnLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum,
+ QSizePolicy::MinimumExpanding));
+
+ lbl = new QLabel(i18n("Layout &icon style:"), page);
+ vlayout->addWidget(lbl);
+
+ cbxIconType = new QComboBox(page);
+ cbxIconType->setEditable(false);
+ cbxIconType->insertItem(i18n("Country flag"));
+ cbxIconType->insertItem(i18n("Language code"));
+ cbxIconType->insertItem(i18n("Flag and code"));
+ QObject::connect(cbxIconType, SIGNAL(activated(int)), this, SLOT(slotIconTypeSelected(int)));
+ vlayout->addWidget(cbxIconType);
+ lbl->setBuddy(cbxIconType);
+ QWhatsThis::add(cbxIconType, i18n("<p>Select the style of icons representing the "
+ "current keyboard layout.\n"
+ "You can choose from the following styles:"
+ "<ul><li><b>Country flag</b> - displays the corresponding contry flag"
+ "<li><b>Language code</b> - displays the language ISO 2-letter code"
+ "<li><b>Flag and code</b> - displays the language code superimposed over the country flag."
+ "</ul></p>"));
+
+ lbl = new QLabel(i18n("&Layout applies to:"), page);
+ vlayout->addWidget(lbl);
+
+ cbxGroupScope = new QComboBox(page);
+ cbxGroupScope->setEditable(false);
+ cbxGroupScope->insertItem(i18n("All windows"));
+ cbxGroupScope->insertItem(i18n("Windows of one application"));
+ cbxGroupScope->insertItem(i18n("One window"));
+ vlayout->addWidget(cbxGroupScope);
+ lbl->setBuddy(cbxGroupScope);
+ QWhatsThis::add(cbxGroupScope, i18n("<p>Select what windows the currently selected "
+ "keyboard layout applies to:\n"
+ "<ul><li><b>All windows</b> - one layout applies to all windows on your desktop\n"
+ "<li><b>Windows of one application</b> - layout applies to one application; each "
+ "application can have its own layout. When you switch between applications, layout follows the active application\n"
+ "<li><b>One window</b> - layout applies to one window only; each window can have its own layout. "
+ "When you switch between windows, layout follows the active window.</ul></p>"));
+
+ chkToggleMode = new QCheckBox(i18n("Use \"&Toggle Mode\""), page);
+ vlayout->addWidget(chkToggleMode);
+ QWhatsThis::add(chkToggleMode, i18n("Toggle mode is useful when you have more than two keyboard "
+ "layouts defined. When toggle mode is on your normal layout switch key toggles between two most frequently used layouts. "
+ "To activate other layouts use KKBSwitch's tray popup menu"));
+
+ /*chkPerwindowGroup = new QCheckBox(i18n("Use &per-window layout"), page);
+ vlayout->addWidget(chkPerwindowGroup);
+ QWhatsThis::add(chkPerwindowGroup, i18n("When this checkbox is checked, "
+ "each window has its own current keyboard layout. When it's unchecked, "
+ "the current layout affects all windows"));*/
+
+ chkAutostart = new QCheckBox(i18n("A&utostart"), page);
+ vlayout->addWidget(chkAutostart);
+ QWhatsThis::add(chkAutostart, i18n("When this checkbox is checked, KKBSwitch "
+ "will start automatically when you log in"));
+}
+
+void KBConfigDlg::setupShortcutsPage()
+{
+ QVBox *box = addVBoxPage(i18n("Sho&rtcuts"));
+ chkUseShortcuts = new QCheckBox(i18n("Use shortcuts to &activate keyboard layouts"), box);
+ connect(chkUseShortcuts, SIGNAL(toggled(bool)), this, SLOT(slotUseShortcutsToggled(bool)));
+ QWhatsThis::add(chkUseShortcuts, i18n("Check this checkbox to be able to quickly "
+ "activate any keyboard layout with keyboard shorcuts. Once this checkbox "
+ "is checked, you can adjust the shortcuts at the key chooser pane below. "
+ "Especially useful if you have three or four keyboard layouts configured"));
+
+ keyChooser = new SmallerKeyChooser(m_kbconf->keys(), box);
+}
+
+/** Display the current KBSwitch configuration in the dialog */
+void KBConfigDlg::showConfig(){
+ int i;
+ KBGroup *group;
+ KConfig *conf = kapp->config();
+
+ m_iconpaths.clear();
+ conf->setGroup(ICONS_SECTION);
+ for (i = 0; i < m_kbconf->groupCount(); i++) {
+ group = m_kbconf->getGroup(i);
+ (void) new BoldListBoxItem(lbGroups, group->getPixmap(), group->getName(),
+ i == m_default_groupno);
+ //m_iconpaths.append(conf->readEntry(KBConfig::entryForGroup(i)));
+ m_iconpaths.append(group->getIconPath());
+ }
+ if (m_kbconf->groupCount() > 0) lbGroups->setCurrentItem(0);
+ lbGroups->setMinimumHeight(lbGroups->itemHeight() * (m_kbconf->groupCount() + 1));
+ cbxIconType->setCurrentItem(m_kbconf->icon_style());
+ cbxGroupScope->setCurrentItem(m_kbconf->group_scope());
+ chkToggleMode->setChecked(m_kbconf->toggle_mode());
+ //chkPerwindowGroup->setChecked(m_kbconf->perwindow_group());
+ chkAutostart->setChecked(m_kbconf->autostart());
+ chkUseShortcuts->setChecked(m_kbconf->use_shortcuts());
+ slotUseShortcutsToggled(m_kbconf->use_shortcuts());
+}
+
+/** Fire up "Pick Icon" dialog */
+void KBConfigDlg::slotPickIcon(){
+ int index = lbGroups->currentItem();
+ QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
+ KBPickIconDlg dlg(m_iconpaths[index], *(lbGroups->pixmap(index)), this);
+ QApplication::restoreOverrideCursor();
+ if (dlg.exec()) {
+ QString path = dlg.getIconPath();
+ KBGroup *group = m_kbconf->getGroup(index);
+ if (!path.isEmpty() && path != group->getIconPath()) {
+ kapp->config()->writeEntry(group->getName()/*KBConfig::entryForGroup(index)*/, path);
+ redrawIcons(KBConfig::IconStyle(cbxIconType->currentItem()));
+ checkIconDefault(index);
+ }
+ }
+}
+
+void KBConfigDlg::slotSetDefaultGroup()
+{
+ int new_default_group = lbGroups->currentItem();
+ if (m_default_groupno != new_default_group) {
+ BoldListBoxItem *item = dynamic_cast<BoldListBoxItem*>(lbGroups->item(m_default_groupno));
+ item->setBold(false);
+ m_default_groupno = new_default_group;
+ // NB: don't use selectedItem(); it's not present in Qt 3.0, and
+ // we want to maintain compatibility with it
+ int curitem = lbGroups->currentItem();
+ if (curitem > -1) { // should not be -1, but just in case
+ item = dynamic_cast<BoldListBoxItem*>(lbGroups->item(curitem));
+ item->setBold(true);
+ lbGroups->triggerUpdate(false);
+ }
+ }
+}
+
+/** No descriptions */
+void KBConfigDlg::slotLayoutSelected(){
+ btnChangeIcon->setEnabled(lbGroups->currentItem() != -1 &&
+ iconTypeShowsFlag(KBConfig::IconStyle(cbxIconType->currentItem())));
+ checkIconDefault(lbGroups->currentItem());
+ btnSetDefaultGroup->setEnabled(lbGroups->currentItem() != -1 &&
+ lbGroups->currentItem() != m_default_groupno);
+}
+
+/** No descriptions */
+void KBConfigDlg::slotListBoxExecuted(QListBoxItem *){
+ if (iconTypeShowsFlag(KBConfig::IconStyle(cbxIconType->currentItem())))
+ slotPickIcon();
+}
+
+/** No descriptions */
+void KBConfigDlg::saveConfig(){
+ QString path;
+ const QPixmap *pix;
+ KConfig *conf = kapp->config();
+ conf->setGroup(ICONS_SECTION);
+ for (int i = 0; i < m_kbconf->groupCount(); i++) {
+ path = m_iconpaths[i];
+ if (!path.isEmpty()) m_kbconf->getGroup(i)->setIconPath(path);
+ //if (!path.isEmpty() && path != m_kbconf->getGroup(i)->getIconPath())
+ // conf->writeEntry(KBConfig::entryForGroup(i), path);
+ pix = lbGroups->pixmap(i);
+ if (pix) m_kbconf->getGroup(i)->setPixmap(*pix);
+ }
+ m_kbconf->set_toggle_mode(chkToggleMode->isChecked());
+ m_kbconf->set_group_scope(KBConfig::GroupScope(cbxGroupScope->currentItem()));
+ m_kbconf->set_default_groupno(m_default_groupno);
+ //m_kbconf->set_perwindow_group(chkPerwindowGroup->isChecked());
+ m_kbconf->set_icon_style(KBConfig::IconStyle(cbxIconType->currentItem()));
+ m_kbconf->set_autostart(chkAutostart->isChecked());
+ m_kbconf->set_use_shortcuts(chkUseShortcuts->isChecked());
+ keyChooser->commitChanges();
+ m_kbconf->checkKeysEnabled();
+ m_kbconf->save(conf);
+
+ //m_kbconf->notifyChanged();
+ conf->sync();
+}
+
+/** No descriptions */
+void KBConfigDlg::slotOk(){
+ saveConfig();
+ KDialogBase::slotOk();
+}
+
+/** No descriptions */
+void KBConfigDlg::slotApply(){
+ saveConfig();
+ KDialogBase::slotApply();
+}
+
+void KBConfigDlg::slotIconTypeSelected(int index)
+{
+ KBConfig::IconStyle icon_style = KBConfig::IconStyle(index);
+ redrawIcons(icon_style);
+ slotLayoutSelected();
+}
+
+void KBConfigDlg::redrawIcons(KBConfig::IconStyle icon_style)
+{
+ QValueVector<QPixmap> pixlist;
+ m_kbconf->drawIcons(icon_style, &pixlist, &m_iconpaths);
+ int curIndex = lbGroups->currentItem();
+ // NB: don't use count(), use size(); count() is not present in Qt 3.0, and
+ // we want to maintain compatibility with it
+ for (unsigned int i = 0; i < pixlist.size(); i++) {
+ BoldListBoxItem *curItem = dynamic_cast<BoldListBoxItem*>(lbGroups->item(i));
+ lbGroups->changeItem(new BoldListBoxItem(NULL, pixlist[i],
+ curItem->text(), curItem->bold()), i);
+ }
+ lbGroups->setCurrentItem(curIndex);
+}
+
+void KBConfigDlg::slotCancel()
+{
+ KConfig *config = kapp->config();
+ config->rollback();
+ config->reparseConfiguration();
+ KDialogBase::slotCancel();
+}
+
+void KBConfigDlg::slotUseShortcutsToggled(bool on)
+{
+ keyChooser->setEnabled(on);
+}
+
+
+/*!
+ \fn KBConfigDlg::slotSetDefaultIcon()
+ */
+void KBConfigDlg::slotSetDefaultIcon()
+{
+ int index = lbGroups->currentItem();
+ kapp->config()->setGroup(ICONS_SECTION);
+ kapp->config()->deleteEntry(m_kbconf->getGroup(index)->getName()/*KBConfig::entryForGroup(index)*/);
+ redrawIcons(KBConfig::IconStyle(cbxIconType->currentItem()));
+}
+
+
+/*!
+ \fn KBConfigDlg::checkIconDefault()
+ */
+void KBConfigDlg::checkIconDefault(int index)
+{
+ KConfig *conf = kapp->config();
+ if (index == -1 || ! iconTypeShowsFlag(KBConfig::IconStyle(cbxIconType->currentItem()))) {
+ btnSetDefaultIcon->setEnabled(false);
+ }
+ else {
+ conf->setGroup(ICONS_SECTION);
+ btnSetDefaultIcon->setEnabled(!conf->readEntry(m_kbconf->getGroup(index)->getName()/*KBConfig::entryForGroup(index)*/).isNull());
+ }
+}
diff --git a/kkbswitch/kbconfigdlg.h b/kkbswitch/kbconfigdlg.h
new file mode 100644
index 0000000..f708a65
--- /dev/null
+++ b/kkbswitch/kbconfigdlg.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ kbconfigdlg.h - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBCONFIGDLG_H
+#define KBCONFIGDLG_H
+
+#include <kdialogbase.h>
+#include "kbconfig.h"
+
+class QWidget;
+class QCheckBox;
+class QPushButton;
+class QComboBox;
+class QStringList;
+class KKeyChooser;
+
+
+/**Configuration dialog for KKBSwitch
+ *@author Leonid Zeitlin
+ */
+
+class KBConfigDlg : public KDialogBase {
+ Q_OBJECT
+public:
+ KBConfigDlg(KBConfig *kbconf, QWidget *parent=0, const char *name=0);
+ ~KBConfigDlg();
+private: // Private attributes
+ /** */
+ KListBox *lbGroups;
+ /** */
+ QCheckBox *chkToggleMode;
+ //QCheckBox *chkPerwindowGroup;
+ QCheckBox *chkAutostart;
+ QPushButton *btnChangeIcon;
+ QPushButton *btnSetDefaultIcon;
+ QPushButton *btnSetDefaultGroup;
+ QComboBox *cbxIconType;
+ QComboBox *cbxGroupScope;
+ KKeyChooser *keyChooser;
+ QCheckBox *chkUseShortcuts;
+ QStringList m_iconpaths;
+ int m_default_groupno;
+ KBConfig *m_kbconf;
+ /** Display the current KBSwitch configuration in the dialog */
+ void showConfig();
+ void saveConfig();
+ void redrawIcons(KBConfig::IconStyle icon_style);
+ void setupGeneralPage();
+ void setupShortcutsPage();
+ void checkIconDefault(int index);
+private slots: // Private slots
+ /** Fire up "Pick Icon" dialog */
+ void slotPickIcon();
+ void slotSetDefaultGroup();
+ /** No descriptions */
+ void slotLayoutSelected();
+ /** No descriptions */
+ void slotListBoxExecuted(QListBoxItem *item);
+ void slotIconTypeSelected(int index);
+ void slotUseShortcutsToggled(bool on);
+ void slotSetDefaultIcon();
+protected: // Protected methods
+ /** No descriptions */
+ virtual void slotApply();
+ /** No descriptions */
+ virtual void slotOk();
+ virtual void slotCancel();
+};
+
+#endif
diff --git a/kkbswitch/kbgroup.cpp b/kkbswitch/kbgroup.cpp
new file mode 100644
index 0000000..77d999f
--- /dev/null
+++ b/kkbswitch/kbgroup.cpp
@@ -0,0 +1,26 @@
+/***************************************************************************
+ kbgroup.cpp - description
+ -------------------
+ begin : Wed Jul 4 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kbgroup.h"
+#include <kdebug.h>
+
+KBGroup::KBGroup(const QString& name){
+ m_name = name;
+}
+
+KBGroup::~KBGroup(){
+}
diff --git a/kkbswitch/kbgroup.h b/kkbswitch/kbgroup.h
new file mode 100644
index 0000000..0c5997c
--- /dev/null
+++ b/kkbswitch/kbgroup.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ kbgroup.h - description
+ -------------------
+ begin : Wed Jul 4 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBGROUP_H
+#define KBGROUP_H
+
+#include <qpixmap.h>
+#include <qstring.h>
+
+/**A helper class the holds keyboard group's name and pixmap
+ *@author Leonid Zeitlin
+ */
+
+class KBGroup {
+public:
+ KBGroup(const QString& name);
+ ~KBGroup();
+ /** */
+ const QPixmap& getPixmap() { return m_pixmap; }
+ /** No descriptions */
+ const QString& getName() { return m_name; }
+ /** No descriptions */
+ void setPixmap(const QPixmap& pixmap) { m_pixmap = pixmap; }
+ const QString& getIconPath() { return m_iconpath; }
+ void setIconPath(const QString &iconpath) { m_iconpath = iconpath; }
+private: // Private attributes
+ /** */
+ QString m_name;
+ /** */
+ QPixmap m_pixmap;
+ QString m_iconpath;
+};
+
+#endif
diff --git a/kkbswitch/kbpickicondlg.cpp b/kkbswitch/kbpickicondlg.cpp
new file mode 100644
index 0000000..d745f7c
--- /dev/null
+++ b/kkbswitch/kbpickicondlg.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ kbpickicondlg.cpp - description
+ -------------------
+ begin : Sat Jul 21 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kbpickicondlg.h"
+
+#include <qvbox.h>
+#include <qdir.h>
+#include <qwhatsthis.h>
+#include <qpushbutton.h>
+#include <qimage.h>
+
+#include <kdeversion.h>
+#include <klocale.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kstandarddirs.h>
+#else
+ #include <kstddirs.h>
+#endif
+#include <kglobal.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+
+#include "kbconfig.h"
+#include "pathlistboxitem.h"
+
+KBPickIconDlg::KBPickIconDlg(const QString &currentPath, const QPixmap &currentPixmap,
+ QWidget *parent, const char *name )
+ : KDialogBase(parent, name, true /*modal*/, i18n("Pick an icon") /*caption*/, Ok | Cancel) {
+ QVBox *page = makeVBoxMainWidget();
+
+ lbIcons = new KListBox(page);
+ QObject::connect(lbIcons, SIGNAL(doubleClicked(QListBoxItem*)),
+ this, SLOT(slotOk()));
+ QObject::connect(lbIcons, SIGNAL(returnPressed(QListBoxItem*)),
+ this, SLOT(slotOk()));
+ QWhatsThis::add(lbIcons, i18n("Select one of the icons"));
+
+ QPushButton *btnBrowse = new QPushButton(i18n("&Browse..."), page);
+ QObject::connect(btnBrowse, SIGNAL(clicked()), this, SLOT(slotBrowseForIcon()));
+ QWhatsThis::add(btnBrowse, i18n("Browse for an image file to use as an icon"));
+
+ loadCountryFlags();
+
+ // I am told in Red Hat 9 standard KDE flag pixmaps are missing.
+ // Workaround: we have to simulate them by rescaling GKB's pixmaps
+ if (lbIcons->count() == 0) {
+ loadGkbCountryFlags();
+ }
+ lbIcons->sort();
+ showCurrentPath(currentPath, currentPixmap);
+ lbIcons->setFocus();
+}
+
+KBPickIconDlg::~KBPickIconDlg(){
+}
+
+/** Get the path name of the selected icon. Returns empty string if no icon selected */
+QString KBPickIconDlg::getIconPath(){
+ QListBoxItem *item = lbIcons->selectedItem();
+ if (item)
+ return dynamic_cast<PathListBoxItem*>(item)->path;
+ else return QString::null; // should not happen
+}
+
+/** No descriptions */
+const QPixmap* KBPickIconDlg::getIcon(){
+ if (lbIcons->currentItem() != -1)
+ return lbIcons->pixmap(lbIcons->currentItem());
+ else return NULL;
+}
+
+/** Browse for an arbitrary icon file */
+void KBPickIconDlg::slotBrowseForIcon()
+{
+ QString iconPath = KFileDialog::getOpenFileName(QString::null,
+ i18n("*.png *.jpg *.gif *.xpm|Icon files (*.png, *.jpg, *.gif, *.xpm)\n*.*|All files (*.*)"));
+ if (iconPath.isEmpty()) return;
+ QImage img;
+ if (img.load(iconPath)) {
+ double aspectRatio = img.width() / img.height();
+ QString message = QString::null;
+ bool too_big, too_wide, too_narrow;
+ too_narrow = aspectRatio < FLAG_ICON_WIDTH / FLAG_ICON_HEIGHT - 0.1;
+ too_wide = aspectRatio > FLAG_ICON_WIDTH / FLAG_ICON_HEIGHT + 0.1;
+ too_big = img.width() > FLAG_ICON_WIDTH * 2;
+ if (too_big || too_narrow || too_wide) {
+ message = i18n("The size of this image (%1 by %2) is not good.\n"
+ "Preferred size for the layout icons is %3 by %4.\n")
+ .arg(img.width()).arg(img.height()).arg(FLAG_ICON_WIDTH).arg(FLAG_ICON_HEIGHT);
+ if (too_big) {
+ QString msg_tail = "";
+ if (too_wide) msg_tail = i18n(" and also too wide");
+ else if (too_narrow) msg_tail += i18n(" and also too narrow");
+ message += i18n("This image is too big%1.").arg(msg_tail);
+ }
+ else if (too_wide) message += i18n("This image is too wide.");
+ else if (too_narrow) message += i18n("This image is too narrow.");
+ message += "\n";
+ message += i18n("KKBSwitch will scale it to appropriate size, but the result may not look very good.\n"
+ "Are you sure you want to use this image?");
+ if (KMessageBox::questionYesNo(this, message) != KMessageBox::Yes) return;
+ }
+ if (img.width() > FLAG_ICON_WIDTH + 3 || img.height() > FLAG_ICON_HEIGHT + 3)
+ img = img.smoothScale(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT);
+ QPixmap pix;
+ pix.convertFromImage(img);
+ PathListBoxItem *item = new PathListBoxItem(lbIcons, pix, QFileInfo(iconPath).fileName(),
+ iconPath);
+ lbIcons->setSelected(item, true);
+ lbIcons->centerCurrentItem();
+ }
+ else KMessageBox::error(this, i18n("Cannot read icon from file %1. "
+ "Either it is not an image file or it is corrupt.").arg(iconPath));
+}
+
+void KBPickIconDlg::loadCountryFlags()
+{
+ QPixmap pix;
+ QDir dir;
+ QStringList locales;
+ QString path;
+ QStringList dirs = KGlobal::dirs()->findDirs("locale", "l10n");
+
+ for (QStringList::Iterator dirIter = dirs.begin(); dirIter != dirs.end(); dirIter++) {
+ dir.setPath(*dirIter);
+ locales = dir.entryList(QDir::Dirs, QDir::Name);
+ for (QStringList::Iterator iter = locales.begin(); iter != locales.end(); iter++) {
+ path = dir.path() + "/" + *iter + "/flag.png";
+ if (*iter != "." && *iter != ".." && pix.load(path)) {
+ KConfig config(dir.path() + "/" + *iter + "/entry.desktop", true, false,
+ "locale" /*doesn't really matter*/);
+ config.setGroup("KCM Locale");
+ new PathListBoxItem(lbIcons, pix, config.readEntry("Name"), path);
+ }
+ }
+ }
+}
+
+void KBPickIconDlg::loadGkbCountryFlags()
+{
+ QDir dir;
+ QString path, code, name;
+ QPixmap pix;
+ QImage img;
+
+ dir.setPath("/usr/share/pixmaps/gkb");
+ const QFileInfoList *icons = dir.entryInfoList(QDir::Files, QDir::Name);
+ if (icons) {
+ QFileInfoListIterator iter(*icons);
+ QFileInfo *info;
+ for (; (info = iter.current()); ++iter) {
+ path = info->filePath();
+ code = info->baseName();
+ if (img.load(path)) {
+ KConfig config("l10n/" + code + "/entry.desktop", true, false, "locale");
+ config.setGroup("KCM Locale");
+ name = config.readEntry("Name");
+ if (!name.isNull()) {
+ pix.convertFromImage(img.smoothScale(FLAG_ICON_WIDTH, FLAG_ICON_HEIGHT));
+ new PathListBoxItem(lbIcons, pix, name, path);
+ }
+ }
+ }
+ }
+}
+
+void KBPickIconDlg::showCurrentPath(const QString &currentPath,
+ const QPixmap &currentPixmap)
+{
+ PathListBoxItem *item = NULL;
+ bool itemFound = false;
+ for (unsigned i = 0; i < lbIcons->count(); i++) {
+ item = dynamic_cast<PathListBoxItem*>(lbIcons->item(i));
+ if (item->path == currentPath) {
+ itemFound = true;
+ break;
+ }
+ }
+ // why this strange manipulation of HScrollBarMode?
+ // Strangely, without it, if the selected item is the last in the listbox, it ends up
+ // being obscured by the horizontal scrollbar
+ lbIcons->setHScrollBarMode(QScrollView::AlwaysOn);
+ if (!itemFound) item = new PathListBoxItem(lbIcons, currentPixmap,
+ QFileInfo(currentPath).fileName(), currentPath);
+ lbIcons->updateScrollBars();
+ lbIcons->setSelected(item, true);
+ lbIcons->ensureCurrentVisible();
+ lbIcons->setHScrollBarMode(QScrollView::Auto);
+}
diff --git a/kkbswitch/kbpickicondlg.h b/kkbswitch/kbpickicondlg.h
new file mode 100644
index 0000000..b6abb16
--- /dev/null
+++ b/kkbswitch/kbpickicondlg.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ kbpickicondlg.h - description
+ -------------------
+ begin : Sat Jul 21 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBPICKICONDLG_H
+#define KBPICKICONDLG_H
+
+#include <kdialogbase.h>
+
+class QWidget;
+class QStringList;
+class QPixmap;
+class KListBox;
+
+/**A dialog to pick an icon for a keyboard layout
+ *@author Leonid Zeitlin
+ */
+
+class KBPickIconDlg : public KDialogBase {
+ Q_OBJECT
+public:
+ KBPickIconDlg(const QString &currentPath, const QPixmap &currentPixmap,
+ QWidget *parent=0, const char *name=0);
+ ~KBPickIconDlg();
+ /** Get the path name of the selected icon. Returns empty string if no icon selected */
+ QString getIconPath();
+ /** No descriptions */
+ const QPixmap* getIcon();
+private: // Private attributes
+ /** */
+ //QStringList m_pathnames;
+ //QString m_iconpath;
+ //KIconView *m_iconview;
+ KListBox *lbIcons;
+ //QLabel *lblIcon;
+ //QRadioButton *rbFlags;
+ //QRadioButton *rbBrowse;
+ void loadCountryFlags();
+ void loadGkbCountryFlags();
+ void showCurrentPath(const QString &currentPath, const QPixmap &currentPixmap);
+private slots: // Private slots
+ /** Browse for an arbitrary icon file */
+ void slotBrowseForIcon();
+ /** Respond to user selecting a flag in the icon view */
+ //void slotFlagSelected(QIconViewItem *item);
+};
+
+#endif
diff --git a/kkbswitch/kbswitchapp.cpp b/kkbswitch/kbswitchapp.cpp
new file mode 100644
index 0000000..9dab46a
--- /dev/null
+++ b/kkbswitch/kbswitchapp.cpp
@@ -0,0 +1,379 @@
+/***************************************************************************
+ kbswitchapp.cpp - description
+ -------------------
+ begin : Sun Jul 1 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "config.h"
+#include "kbswitchapp.h"
+#include "kbconfigdlg.h"
+#include "singlewindowwatcher.h"
+#include "windowclasswatcher.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kwinmodule.h>
+
+KBSwitchApp::KBSwitchApp()
+{
+#ifndef HAVE_LIBXKLAVIER
+ //m_kwin_module = NULL;
+ m_watcher = NULL;
+#endif
+ if (!m_xkb.xkbAvailable()) return; // oops! No XKB in the server
+ m_kbconf.load(config());
+ m_cur_groupno = m_next_groupno = -1;
+#ifdef HAVE_LIBXKLAVIER
+ XklSetGroupPerApp(m_kbconf.group_scope() != KBConfig::SCOPE_GLOBAL);
+ if (m_kbconf.toggle_mode())
+ XklSetSecondaryGroupsMask(12); /* binary 1100 */
+#else
+ //resetWindowMap();
+ //enableKWinModule();
+ enableWatcher();
+#endif
+
+ m_intf = new KBSwitchIntf(this, &m_kbconf);
+ QObject::connect(m_intf, SIGNAL(nextGroupSelected()), this, SLOT(slotSelectNextGroup()));
+ QObject::connect(m_intf, SIGNAL(groupSelected(int)), this, SLOT(slotGroupSelected(int)));
+
+ QObject::connect(&m_xkb, SIGNAL(layoutChanged()), this, SLOT(reconfigure()));
+ QObject::connect(&m_xkb, SIGNAL(groupChanged(int)), this, SLOT(slotXkbGroupChanged(int)));
+
+ m_force_group_setting = false;
+ int start_group = m_kbconf.default_groupno();
+
+ m_trayicon = new KBSwitchTrayIcon(&m_kbconf);
+ QObject::connect(m_trayicon, SIGNAL(groupSelected(int)), this,
+ SLOT(slotGroupSelected(int)));
+ QObject::connect(m_trayicon, SIGNAL(clicked()), this, SLOT(slotSelectNextGroup()));
+ QObject::connect(m_trayicon, SIGNAL(preferencesSelected()), this,
+ SLOT(slotPreferences()));
+
+ if (start_group != m_xkb.getGroupNo()) {
+ setStartGroup(start_group);
+ }
+ else {
+ adaptToGroup(start_group);
+ }
+
+ setMainWidget(m_trayicon);
+ m_trayicon->show();
+
+#ifdef HAVE_LIBXKLAVIER
+ XklStartListen();
+#endif
+}
+
+KBSwitchApp::~KBSwitchApp(){
+#ifndef HAVE_LIBXKLAVIER
+ //disableKWinModule();
+ disableWatcher();
+#endif
+}
+
+/** No descriptions */
+bool KBSwitchApp::x11EventFilter(XEvent *e){
+ // let m_xkb process the event and emit signals if necessary
+ m_xkb.processEvent(e);
+ return KApplication::x11EventFilter(e);
+}
+
+/** Update the tray icon to show the flag corresponding to the current keyboard group */
+void KBSwitchApp::updateIcon(int groupno){
+ if (groupno >= 0 && groupno < m_kbconf.groupCount()) { // check just in case
+ m_trayicon->updateTrayIcon(groupno);
+ if (m_kbconf.toggle_mode()) m_trayicon->setToggleGroups(m_cur_groupno, m_next_groupno);
+ }
+}
+
+/** No descriptions */
+void KBSwitchApp::slotGroupSelected(int groupno)
+{
+#ifdef HAVE_LIBXKLAVIER
+ XklAllowOneSwitchToSecondaryGroup();
+ m_xkb.setGroupNo(groupno);
+#else
+ if (m_cur_groupno != groupno) {
+ setGroups(groupno, m_cur_groupno);
+ }
+#endif
+}
+
+/** No descriptions */
+void KBSwitchApp::internalToggleGroups()
+{
+ int tmp = m_next_groupno;
+ m_next_groupno = m_cur_groupno;
+ m_cur_groupno = tmp;
+}
+
+/** No descriptions */
+void KBSwitchApp::forceSetGroup(int groupno)
+{
+ m_force_group_setting = true;
+#ifndef HAVE_LIBXKLAVIER
+ //if (m_active_window != m_window_map.end())
+ // m_active_window.data().groupno = groupno;
+#endif
+ m_xkb.setGroupNo(groupno);
+}
+
+/** No descriptions */
+void KBSwitchApp::slotSelectNextGroup()
+{
+#ifdef HAVE_LIBXKLAVIER
+ m_xkb.setGroupNo(XklGetNextGroup());
+#else
+ //forceSetGroup(m_next_groupno);
+ m_xkb.setGroupNo(m_next_groupno);
+#endif
+}
+
+/** No descriptions */
+void KBSwitchApp::slotPreferences(){
+ KBConfigDlg dlg(&m_kbconf);
+ QObject::connect(&dlg, SIGNAL(okClicked()), m_trayicon, SLOT(slotUpdateIcons()));
+ QObject::connect(&dlg, SIGNAL(applyClicked()), m_trayicon, SLOT(slotUpdateIcons()));
+ QObject::connect(&dlg, SIGNAL(okClicked()), this, SLOT(slotPrefChanged()));
+ QObject::connect(&dlg, SIGNAL(applyClicked()), this, SLOT(slotPrefChanged()));
+ dlg.exec();
+}
+
+/** Called when XKeyboard configuration changes */
+void KBSwitchApp::reconfigure(){
+ m_kbconf.load(config());
+ m_trayicon->reconfigure();
+
+ // make sure default group is still valid
+ if (m_kbconf.default_groupno() >= m_xkb.getNumKbdGroups())
+ m_kbconf.set_default_groupno(0);
+
+ int groupno = m_xkb.getGroupNo();
+ if (groupno >= m_xkb.getNumKbdGroups()) {
+ // current group no longer valid, reset to default group
+ setStartGroup(m_kbconf.default_groupno());
+ }
+ else if (!m_force_group_setting) {
+ adaptToGroup(groupno);
+ }
+#ifndef HAVE_LIBXKLAVIER
+ //resetWindowMap();
+ if (m_watcher) m_watcher->reset();
+#endif
+}
+
+/** Respond to XKB changing the current group */
+void KBSwitchApp::slotXkbGroupChanged(int groupno){
+#ifdef HAVE_LIBXKLAVIER
+ updateIcon(groupno);
+/* XWindowAttributes attrs;
+ XGetWindowAttributes(qt_xdisplay(), qt_xrootwin(), &attrs);
+ kdDebug() << "root event mask is " << attrs.your_event_mask << endl;
+ kdDebug() << "SubstructureNotifyMask is " <<
+ ((attrs.your_event_mask & SubstructureNotifyMask) ? "ON" : "OFF") << endl;*/
+#else
+ bool accept = false;
+ if (m_force_group_setting) { // the change of group is forced by us
+ if (groupno == m_cur_groupno) { // the group is what we wanted, fine
+ m_force_group_setting = false;
+ accept = true;
+ }
+ else { // oops, not the group we expected
+ forceSetGroup(m_cur_groupno);
+ }
+ }
+ else { // the change is caused by something external, we didn't request it
+ if (m_kbconf.toggle_mode() && groupno != m_next_groupno) { // toggle mode, and the group is not correct
+ m_xkb.setGroupNo(m_next_groupno);
+ }
+ else { // adjust to this group
+ if (m_kbconf.toggle_mode()) internalToggleGroups();
+ else {
+ m_cur_groupno = groupno;
+ m_next_groupno = m_kbconf.getNextGroup(groupno);
+ }
+ accept = true;
+ }
+ }
+ if (accept) {
+ updateIcon(groupno);
+ if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
+ }
+ /*if (m_kbconf.toggle_mode() && !force_group_setting && groupno != m_next_groupno) {
+ forceSetGroup(m_next_groupno);
+ }
+ else {
+ updateIcon(groupno);
+ force_group_setting = false;
+ if (m_kbconf.toggle_mode()) internalToggleGroups();
+ else {
+ kdDebug() << "slotXkbGroupChanged, change group to " << groupno << endl;
+ m_cur_groupno = groupno;
+ m_next_groupno = m_kbconf.getNextGroup(groupno);
+ }
+ if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
+ }*/
+#endif
+}
+
+/** Set the keyboard to the given group and set internal variable accordingly */
+void KBSwitchApp::setStartGroup(int start_group){
+ /*m_next_groupno = start_group;
+ if (m_kbconf.toggle_mode()) {
+ m_cur_groupno = getNextGroup(start_group);
+ }
+ else {
+ m_cur_groupno = start_group;
+ }
+ forceSetGroup(m_next_groupno);*/
+ setGroups(start_group, m_kbconf.getNextGroup(start_group));
+}
+
+/** adapt internal state to the given group */
+void KBSwitchApp::adaptToGroup(int groupno) {
+ if (! m_kbconf.toggle_mode() || // if not in toggle mode
+ (m_cur_groupno != groupno // or in toggle mode and internal variables are invalid
+ || m_next_groupno >= m_kbconf.groupCount()
+ || m_next_groupno == m_cur_groupno)) {
+ m_cur_groupno = groupno;
+ m_next_groupno = m_kbconf.getNextGroup(groupno);
+ }
+#ifndef HAVE_LIBXKLAVIER
+ if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
+ /*if (m_active_window != m_window_map.end()) {
+ m_active_window.data().groupno = groupno;
+ m_active_window.data().next_groupno = m_next_groupno;
+ }*/
+#endif
+ updateIcon(groupno);
+}
+
+/*void KBSwitchApp::slotWindowChanged(WId activeWindow)
+{
+#ifndef HAVE_LIBXKLAVIER
+ m_active_window = m_window_map.find(activeWindow);
+ if (m_active_window == m_window_map.end())
+ addWindowToMap(activeWindow);
+ if (m_active_window.data().groupno != m_cur_groupno) {
+ setGroups(m_active_window.data().groupno, m_active_window.data().next_groupno);
+ }
+ else m_next_groupno = m_active_window.data().next_groupno;
+#endif
+}*/
+
+void KBSwitchApp::slotWindowChanged(int groupno, int next_groupno)
+{
+ if (groupno != m_cur_groupno) {
+ setGroups(groupno, next_groupno);
+ }
+ else m_next_groupno = next_groupno;
+}
+
+/*void KBSwitchApp::slotWindowRemoved(WId window)
+{
+#ifndef HAVE_LIBXKLAVIER
+ m_window_map.remove(window);
+#endif
+}
+
+#ifndef HAVE_LIBXKLAVIER
+void KBSwitchApp::resetWindowMap()
+{
+ WId active_window_id;
+
+ m_window_map.clear();
+
+ if (m_kwin_module && (active_window_id = m_kwin_module->activeWindow()))
+ addWindowToMap(active_window_id);
+ else
+ m_active_window = m_window_map.end();
+}*/
+
+/** Enable window manager notifications */
+/*void KBSwitchApp::enableKWinModule()
+{
+ if (m_kwin_module == NULL) {
+ m_kwin_module = new KWinModule();
+ connect(m_kwin_module, SIGNAL(activeWindowChanged(WId)), SLOT(slotWindowChanged(WId)));
+ connect(m_kwin_module, SIGNAL(windowRemoved(WId)), SLOT(slotWindowRemoved(WId)));
+ resetWindowMap();
+ if (m_cur_groupno != -1 && m_cur_groupno != m_kbconf.default_groupno())
+ setStartGroup(m_kbconf.default_groupno());
+ }
+}*/
+
+/** Disable window manager notifications */
+/*void KBSwitchApp::disableKWinModule()
+{
+ if (m_kwin_module) {
+ m_kwin_module->disconnect();
+ delete m_kwin_module;
+ m_kwin_module = NULL;
+ resetWindowMap();
+ }
+}*/
+
+/** adds a new window to the internal window map */
+/*void KBSwitchApp::addWindowToMap(WId window_id)
+{
+ KBWinInfo wininfo = { m_kbconf.default_groupno(),
+ m_kbconf.getNextGroup(m_kbconf.default_groupno()) };
+
+ m_active_window = m_window_map.insert(window_id, wininfo);
+}
+#endif*/
+
+void KBSwitchApp::enableWatcher()
+{
+ if (!m_watcher) {
+ m_watcher_type = m_kbconf.group_scope();
+ if (m_watcher_type == KBConfig::SCOPE_WINDOW)
+ m_watcher = new SingleWindowWatcher(&m_kbconf, this);
+ else if (m_watcher_type == KBConfig::SCOPE_CLASS)
+ m_watcher = new WindowClassWatcher(&m_kbconf, this);
+ else return; // if scope is global, don't create watcher
+ connect(m_watcher, SIGNAL(windowChanged(int, int )),
+ SLOT(slotWindowChanged(int, int)));
+ }
+}
+
+void KBSwitchApp::disableWatcher()
+{
+ if (m_watcher) {
+ m_watcher->disconnect();
+ delete m_watcher;
+ m_watcher = NULL;
+ }
+}
+
+/** React to a change in KKBSwitch's user preferences,
+ * made by user in Configure dialog */
+void KBSwitchApp::slotPrefChanged()
+{
+#ifndef HAVE_LIBXKLAVIER
+ if (m_kbconf.group_scope() != m_watcher_type) {
+ disableWatcher();
+ enableWatcher();
+ }
+#endif
+}
+
+/** Set the current and next groups */
+void KBSwitchApp::setGroups(int group, int next_group)
+{
+ m_cur_groupno = group;
+ m_next_groupno = next_group;
+ forceSetGroup(group);
+}
diff --git a/kkbswitch/kbswitchapp.h b/kkbswitch/kbswitchapp.h
new file mode 100644
index 0000000..d08147d
--- /dev/null
+++ b/kkbswitch/kbswitchapp.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+ kbswitchapp.h - description
+ -------------------
+ begin : Sun Jul 1 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBSWITCHAPP_H
+#define KBSWITCHAPP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdeversion.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kuniqueapplication.h>
+#else
+ #include <kuniqueapp.h>
+#endif
+
+//#include <qmap.h>
+
+#include "kbgroup.h"
+#include "kbswitchtrayicon.h"
+#include "kbconfig.h"
+#include "xkeyboard.h"
+#include "kbswitchintf.h"
+#include "windowwatcher.h"
+
+/*class KWinModule;
+
+typedef struct _KBWinInfo {
+ int groupno;
+ int next_groupno;
+} KBWinInfo;
+
+typedef QMap<WId, KBWinInfo> KBWindowMap;*/
+
+/**
+ *@author Leonid Zeitlin
+ */
+
+class KBSwitchApp : public KUniqueApplication {
+ Q_OBJECT
+public:
+ KBSwitchApp();
+ ~KBSwitchApp();
+protected: // Protected methods
+ /** No descriptions */
+ bool x11EventFilter(XEvent *e);
+private: // Private attributes
+ /** */
+ bool m_force_group_setting;
+ int m_cur_groupno;
+ int m_next_groupno;
+ XKeyboard m_xkb;
+ /** */
+ KBSwitchTrayIcon * m_trayicon;
+ /** No descriptions */
+ KBConfig m_kbconf;
+ KBSwitchIntf *m_intf;
+#ifndef HAVE_LIBXKLAVIER
+ /** Window manager interface */
+ //KWinModule *m_kwin_module;
+ /** Maps Window IDs to their keyboard groups */
+ //KBWindowMap m_window_map;
+ //KBWindowMap::iterator m_active_window;
+ WindowWatcher *m_watcher;
+ KBConfig::GroupScope m_watcher_type;
+#endif
+private: // Private methods
+ /** Update the tray icon to show the flag corresponding to the current keyboard group */
+ void updateIcon(int groupno);
+ /** No descriptions */
+ void internalToggleGroups();
+ /** No descriptions */
+ void forceSetGroup(int groupno);
+ /** No descriptions */
+ /*int getNextGroup(int groupno) {
+ return groupno >= m_kbconf.groupCount() - 1 ? 0 : groupno + 1;
+ }*/
+ /** No descriptions */
+ void setStartGroup(int start_group);
+ void adaptToGroup(int groupno);
+#ifndef HAVE_LIBXKLAVIER
+ /** initialize Window groups map */
+ //void resetWindowMap();
+ /** Disable window manager notifications */
+ //void disableKWinModule();
+ /** Enable window manager notifications */
+ //void enableKWinModule();
+ /** adds a new window to the internal window map */
+ //void addWindowToMap(WId window_id);
+ void enableWatcher();
+ void disableWatcher();
+#endif
+ /** Set the current and next groups */
+ void setGroups(int group, int next_group);
+private slots: // Private slots
+ /** No descriptions */
+ void slotGroupSelected(int groupno);
+ /** No descriptions */
+ void slotSelectNextGroup();
+ /** No descriptions */
+ void slotPreferences();
+ /** No descriptions */
+ void reconfigure();
+ /** Respond to XKB changing the current group */
+ void slotXkbGroupChanged(int groupno);
+ /** Respond to changing of active window - active it's kb group */
+ //void slotWindowChanged(WId activeWindow);
+ /** Respond to removal of a window - remote it from Window groups map */
+ //void slotWindowRemoved(WId window);
+ void slotWindowChanged(int groupno, int next_groupno);
+ /** React to a change in KKBSwitch's user preferences,
+ * made by user in Configure dialog */
+ void slotPrefChanged();
+};
+
+#endif
diff --git a/kkbswitch/kbswitchintf.cpp b/kkbswitch/kbswitchintf.cpp
new file mode 100644
index 0000000..4e95839
--- /dev/null
+++ b/kkbswitch/kbswitchintf.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ kbswitchintf.cpp - description
+ -------------------
+ begin : Sun Aug 12 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "kbswitchintf.h"
+//#include <kapp.h>
+
+KBSwitchIntf::KBSwitchIntf(QObject *parent, KBConfig *conf)
+ : QObject(parent, "KBSwitchIntf"), DCOPObject("KBSwitchIntf")
+{
+ m_kbconf = conf;
+}
+
+KBSwitchIntf::~KBSwitchIntf(){
+}
+
+int KBSwitchIntf::getNumKbdGroups()
+{
+ return m_kbconf->groupCount();
+}
+
+ASYNC KBSwitchIntf::selectNextGroup()
+{
+ emit nextGroupSelected();
+}
+
+ASYNC KBSwitchIntf::selectGroup(int groupno)
+{
+ emit groupSelected(groupno);
+}
+
+QStringList KBSwitchIntf::getGroupNames()
+{
+ QStringList result;
+ for (int i = 0; i < m_kbconf->groupCount(); i++)
+ result.append(m_kbconf->getGroup(i)->getName());
+ return result;
+}
diff --git a/kkbswitch/kbswitchintf.h b/kkbswitch/kbswitchintf.h
new file mode 100644
index 0000000..16466c0
--- /dev/null
+++ b/kkbswitch/kbswitchintf.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ kbswitchintf.h - description
+ -------------------
+ begin : Sun Aug 12 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBSWITCHINTF_H
+#define KBSWITCHINTF_H
+
+#include <dcopobject.h>
+#include <qobject.h>
+#include <qstringlist.h>
+
+#include "kbconfig.h"
+
+/**This class implements DCOP bindings for KBSwitch
+ *@author Leonid Zeitlin
+ */
+
+/* Interesting to note: moc failed on this file when the k_dcop section immediately
+ followed the signals section (the error message was "syntax error"). After I
+ separated the signals and k_dcop sections with the public section everything worked.
+ Apparently, the k_dcop "keyword" confuses moc, which is only natural given that
+ moc doesn't know about dcopidl! */
+class KBSwitchIntf : public QObject, public DCOPObject {
+ K_DCOP
+ Q_OBJECT
+signals:
+ void nextGroupSelected();
+ void groupSelected(int groupno);
+public:
+ KBSwitchIntf(QObject *parent, KBConfig *conf);
+ ~KBSwitchIntf();
+private:
+ KBConfig *m_kbconf;
+k_dcop:
+ int getNumKbdGroups();
+ ASYNC selectNextGroup();
+ ASYNC selectGroup(int groupno);
+ QStringList getGroupNames();
+};
+
+#endif
diff --git a/kkbswitch/kbswitchintf.skel b/kkbswitch/kbswitchintf.skel
new file mode 100644
index 0000000..4287ca8
--- /dev/null
+++ b/kkbswitch/kbswitchintf.skel
@@ -0,0 +1 @@
+# \ No newline at end of file
diff --git a/kkbswitch/kbswitchintf_skel.cpp b/kkbswitch/kbswitchintf_skel.cpp
new file mode 100644
index 0000000..e295797
--- /dev/null
+++ b/kkbswitch/kbswitchintf_skel.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** DCOP Skeleton created by dcopidl2cpp from kbswitchintf.kidl
+**
+** WARNING! All changes made in this file will be lost!
+**
+*****************************************************************************/
+
+#include "./kbswitchintf.h"
+
+#include <kdatastream.h>
+
+
+static const char* const KBSwitchIntf_ftable[5][3] = {
+ { "int", "getNumKbdGroups()", "getNumKbdGroups()" },
+ { "ASYNC", "selectNextGroup()", "selectNextGroup()" },
+ { "ASYNC", "selectGroup(int)", "selectGroup(int groupno)" },
+ { "QStringList", "getGroupNames()", "getGroupNames()" },
+ { 0, 0, 0 }
+};
+static const int KBSwitchIntf_ftable_hiddens[4] = {
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+bool KBSwitchIntf::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)
+{
+ if ( fun == KBSwitchIntf_ftable[0][1] ) { // int getNumKbdGroups()
+ replyType = KBSwitchIntf_ftable[0][0];
+ QDataStream _replyStream( replyData, IO_WriteOnly );
+ _replyStream << getNumKbdGroups( );
+ } else if ( fun == KBSwitchIntf_ftable[1][1] ) { // void selectNextGroup()
+ replyType = KBSwitchIntf_ftable[1][0];
+ selectNextGroup( );
+ } else if ( fun == KBSwitchIntf_ftable[2][1] ) { // void selectGroup(int)
+ int arg0;
+ QDataStream arg( data, IO_ReadOnly );
+ arg >> arg0;
+ replyType = KBSwitchIntf_ftable[2][0];
+ selectGroup(arg0 );
+ } else if ( fun == KBSwitchIntf_ftable[3][1] ) { // QStringList getGroupNames()
+ replyType = KBSwitchIntf_ftable[3][0];
+ QDataStream _replyStream( replyData, IO_WriteOnly );
+ _replyStream << getGroupNames( );
+ } else {
+ return DCOPObject::process( fun, data, replyType, replyData );
+ }
+ return true;
+}
+
+QCStringList KBSwitchIntf::interfaces()
+{
+ QCStringList ifaces = DCOPObject::interfaces();
+ ifaces += "KBSwitchIntf";
+ return ifaces;
+}
+
+QCStringList KBSwitchIntf::functions()
+{
+ QCStringList funcs = DCOPObject::functions();
+ for ( int i = 0; KBSwitchIntf_ftable[i][2]; i++ ) {
+ if (KBSwitchIntf_ftable_hiddens[i])
+ continue;
+ QCString func = KBSwitchIntf_ftable[i][0];
+ func += ' ';
+ func += KBSwitchIntf_ftable[i][2];
+ funcs << func;
+ }
+ return funcs;
+}
+
+
diff --git a/kkbswitch/kbswitchtrayicon.cpp b/kkbswitch/kbswitchtrayicon.cpp
new file mode 100644
index 0000000..4a51bfe
--- /dev/null
+++ b/kkbswitch/kbswitchtrayicon.cpp
@@ -0,0 +1,200 @@
+/***************************************************************************
+ kbswitchtrayicon.cpp - description
+ -------------------
+ begin : Wed Jul 4 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kdeversion.h>
+
+#undef USE_BOLD_MENUITEM
+
+#include "kbswitchtrayicon.h"
+#include "xkeyboard.h"
+#ifdef USE_BOLD_MENUITEM
+ #include "boldmenuitem.h"
+#endif
+#include <kpopupmenu.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kstandarddirs.h>
+#else
+ #include <kstddirs.h>
+#endif
+#include <klocale.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kaboutapplication.h>
+#if KDE_VERSION_MAJOR >= 3
+ #include <kapplication.h>
+#else
+ #include <kapp.h>
+#endif
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <qtooltip.h>
+#include <qstyle.h>
+#include <qpainter.h>
+
+#ifdef USE_BOLD_MENUITEM
+static QColor getActiveTextColor(KPopupMenu *menu)
+{
+ int id = menu->insertItem("test text");
+ QMenuItem *item = menu->findItem(id);
+ QStyleOption styleopt = QStyleOption(item);
+ QPainter painter(menu);
+ QColorGroup &cg = menu->colorGroup();
+ KApplication::style().drawControl(QStyle::CE_PopupMenuItem, &painter, menu,
+ menu->contentsRect(), cg, QStyle::Style_Enabled | QStyle::Style_Active,
+ styleopt);
+ menu->removeItem(id);
+ return painter.pen().color();
+}
+#endif
+
+KBSwitchTrayIcon::KBSwitchTrayIcon(KBConfig *conf){
+ QPixmap pix;
+#if KDE_VERSION_MAJOR >= 3
+ KActionCollection *actions = new KActionCollection(this);
+ #define ACTION_PARENT actions
+#else
+ #define ACTION_PARENT this
+#endif
+
+ m_kbconf = conf;
+ //QObject::connect(conf, SIGNAL(changed()), this, SLOT(updateMenuIcons()));
+ KPopupMenu * menu = contextMenu();
+ addLayoutItems(menu, false);
+ QObject::connect(menu, SIGNAL(activated(int)), this, SLOT(slotMenuActivated(int)));
+
+ menu->insertSeparator();
+ KAction *pref = KStdAction::preferences(this, SIGNAL(preferencesSelected()), ACTION_PARENT);
+ pref->plug(menu);
+ KAction *help = KStdAction::help(this, SLOT(slotHelp()), ACTION_PARENT);
+ help->plug(menu);
+ KAction *about = KStdAction::aboutApp(this, SLOT(slotAbout()), ACTION_PARENT);
+ about->plug(menu);
+
+ /*QString path = locate("icon", "hicolor/16x16/apps/locale.png");
+ if (!path.isEmpty()) pix.load(path);*/
+ pix = kapp->iconLoader()->loadIcon("locale", KIcon::Small);
+ menu->changeTitle(menu->idAt(0), pix, i18n("Keyboard Switch"));
+ setAlignment(Qt::AlignHCenter | Qt::AlignCenter);
+}
+
+KBSwitchTrayIcon::~KBSwitchTrayIcon(){
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::slotMenuActivated(int id){
+ if (id >= 0 && id < m_kbconf->groupCount()) emit groupSelected(id);
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::setActiveGroup(int groupno){
+ int i;
+ KPopupMenu *menu = contextMenu();
+ for (i = 0; i < m_kbconf->groupCount(); i++)
+ menu->setItemChecked(i, false);
+ menu->setItemChecked(groupno, true);
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::setToggleGroups(int group1, int group2){
+ int i;
+ bool toggling;
+ KPopupMenu *menu = contextMenu();
+
+ for (i = 0; i < m_kbconf->groupCount(); i++) {
+ toggling = (i == group1 || i == group2);
+#ifdef USE_BOLD_MENUITEM
+ QMenuItem *item = menu->findItem(i);
+ BoldMenuItem *bolditem = dynamic_cast<BoldMenuItem*>(item->custom());
+ bolditem->setBold(toggling);
+#else
+ if (toggling)
+ menu->changeItem(i, m_kbconf->getGroup(i)->getName() + "*");
+ else menu->changeItem(i, m_kbconf->getGroup(i)->getName());
+#endif
+ }
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::mouseReleaseEvent(QMouseEvent *event){
+ if (event->button() == LeftButton) {
+ emit clicked();
+ }
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::slotAbout(){
+ KAboutApplication about;
+ about.exec();
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::updateMenuIcons(){
+ KPopupMenu *menu = contextMenu();
+ for (int i = 0; i < m_kbconf->groupCount(); i++) {
+ menu->changeItem(i, m_kbconf->getGroup(i)->getPixmap(), menu->text(i));
+ }
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::addLayoutItems(KPopupMenu *menu, bool clearOld) {
+ KBGroup *group;
+ int index;
+#ifdef USE_BOLD_MENUITEM
+ QColor active_text_color = getActiveTextColor(menu);
+#endif
+
+ if (clearOld)
+ for (int i = 0; i < XKeyboard::MaxNumKbdGroups; i++)
+ if ((index = menu->indexOf(i)) >= 0) menu->removeItemAt(index);
+
+ for (int i = 0; i < m_kbconf->groupCount(); i++) {
+ group = m_kbconf->getGroup(i);
+#ifdef USE_BOLD_MENUITEM
+ /* the work on BoldMenuItems suspended: see comments in boldmenuitem.h */
+ menu->insertItem(group->getPixmap(),
+ new BoldMenuItem(group->getName(), active_text_color, false), i);
+#else
+ menu->insertItem(group->getPixmap(), group->getName(), i, i + 1);
+#endif
+ }
+}
+
+/** No descriptions */
+void KBSwitchTrayIcon::reconfigure(){
+ addLayoutItems(contextMenu(), true);
+}
+
+/** Update the tray icon display for the given group */
+void KBSwitchTrayIcon::updateTrayIcon(int groupno){
+ const QPixmap& pix = m_kbconf->getGroup(groupno)->getPixmap();
+ setPixmap(pix);
+ setActiveGroup(groupno);
+ QToolTip::remove(this);
+ QToolTip::add(this, m_kbconf->getGroup(groupno)->getName());
+}
+
+/** Update menu and tray icons after configuration has changed */
+void KBSwitchTrayIcon::slotUpdateIcons(){
+ updateTrayIcon(XKeyboard::self()->getGroupNo());
+ updateMenuIcons();
+}
+
+/** Display help */
+void KBSwitchTrayIcon::slotHelp(){
+ kapp->invokeHelp();
+}
diff --git a/kkbswitch/kbswitchtrayicon.h b/kkbswitch/kbswitchtrayicon.h
new file mode 100644
index 0000000..a9b8000
--- /dev/null
+++ b/kkbswitch/kbswitchtrayicon.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ kbswitchtrayicon.h - description
+ -------------------
+ begin : Wed Jul 4 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KBSWITCHTRAYICON_H
+#define KBSWITCHTRAYICON_H
+
+#include <ksystemtray.h>
+
+#include "kbgroup.h"
+#include "kbconfig.h"
+
+/**The tray icon showing the current keyboard group
+ *@author Leonid Zeitlin
+ */
+
+class KBSwitchTrayIcon : public KSystemTray {
+ Q_OBJECT
+public:
+ KBSwitchTrayIcon(KBConfig *conf);
+ ~KBSwitchTrayIcon();
+ /** No descriptions */
+ void setToggleGroups(int group1, int group2);
+ /** No descriptions */
+ void reconfigure();
+ /** Update the tray icon display for the given group */
+ void updateTrayIcon(int groupno);
+signals:
+ void groupSelected(int groupno);
+ /** No descriptions */
+ void clicked();
+ /** No descriptions */
+ void preferencesSelected();
+private slots: // Private slots
+ /** No descriptions */
+ void slotMenuActivated(int id);
+ /** Display help */
+ void slotHelp();
+private: // Private attributes
+ /** */
+ KBConfig *m_kbconf;
+protected: // Protected methods
+ /** No descriptions */
+ void mouseReleaseEvent(QMouseEvent *event);
+public slots: // Public slots
+ /** No descriptions */
+ void slotAbout();
+ /** Update menu and tray icons after configuration has changed */
+ void slotUpdateIcons();
+private: // Private methods
+ /** No descriptions */
+ void addLayoutItems(KPopupMenu *menu, bool clearOld);
+ /** No descriptions */
+ void updateMenuIcons();
+ /** No descriptions */
+ void setActiveGroup(int groupno);
+};
+
+#endif
diff --git a/kkbswitch/kkbswitch.desktop b/kkbswitch/kkbswitch.desktop
new file mode 100644
index 0000000..1eab574
--- /dev/null
+++ b/kkbswitch/kkbswitch.desktop
@@ -0,0 +1,19 @@
+[Desktop Entry]
+Encoding=UTF-8
+Type=Application
+Name=KKBSwitch
+Exec=kkbswitch -caption "%c" %i %m
+MimeTypes=
+Terminal=false
+Icon=keyboard_layout.png
+MiniIcon=keyboard_layout.png
+DocPath=kkbswitch/index.html
+Comment=Keyboard Layout Indicator
+Comment[ru]=Индикатор раскладки клавиатуры
+Comment[uk]=Індикатор розкладки клавіатури
+Terminal=0
+X-KDE-autostart-after=panel
+X-KDE-autostart-condition=kkbswitchrc:Options:autostart:true
+X-KDE-autostart-phase=2
+X-KDE-StartupNotify=false
+Categories=Qt;KDE;Utility;TrayIcon;
diff --git a/kkbswitch/main.cpp b/kkbswitch/main.cpp
new file mode 100644
index 0000000..d803b4d
--- /dev/null
+++ b/kkbswitch/main.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Sun Jul 1 21:57:08 EEST 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <stdlib.h>
+
+//#include "kkbswitch.h"
+#include "kbswitchapp.h"
+
+static const char *description =
+ I18N_NOOP("Keyboard Switch");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+
+static KCmdLineOptions options[] =
+{
+ { 0, 0, 0 }
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+//extern "C" int kdemain(int argc, char *argv[])
+int main(int argc, char *argv[])
+{
+
+ KAboutData aboutData( "kkbswitch", I18N_NOOP("Keyboard Switch"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2001-2005 Leonid Zeitlin", 0, 0, "lz@europe.com");
+ aboutData.addAuthor("Leonid Zeitlin", I18N_NOOP("Creator and maintainer"), "lz@europe.com");
+ aboutData.addCredit("Mikhail Senin", I18N_NOOP("Default group config and per-window groups"),
+ "m_senin@mail.ru");
+ aboutData.addCredit("Rashid N. Achilov", I18N_NOOP("FreeBSD port, feature suggestions"), "achilov@granch.ru");
+ aboutData.addCredit("Vadim Kriklivy (K&K Analitic)", I18N_NOOP("Feature suggestions, Ukrainian translation"),
+ "analitic@vinnitsa.com");
+ aboutData.addCredit("Sergey V Turchin", I18N_NOOP("Autostart patch"),"zerg@altlinux.org");
+ aboutData.addCredit("Stergios Dramis", I18N_NOOP("Greek translation"), "sdramis@egnatia.ee.auth.gr");
+ aboutData.addCredit("Michal Sulek", I18N_NOOP("Slovak translation"), "reloadshot@atlas.sk");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ if (!KUniqueApplication::start()) // starting a second instance - just exit
+ exit(0);
+
+ KBSwitchApp a;
+#ifdef HAVE_LIBXKLAVIER
+ //XklStartListen();
+#endif
+ if (XKeyboard::self()->xkbAvailable())
+ return a.exec();
+ else return -1;
+}
diff --git a/kkbswitch/pathlistboxitem.cpp b/kkbswitch/pathlistboxitem.cpp
new file mode 100644
index 0000000..256b843
--- /dev/null
+++ b/kkbswitch/pathlistboxitem.cpp
@@ -0,0 +1,28 @@
+/***************************************************************************
+ pathlistboxitem.cpp - description
+ -------------------
+ begin : ??? ??? 17 2004
+ copyright : (C) 2004 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "pathlistboxitem.h"
+
+PathListBoxItem::PathListBoxItem(QListBox *listbox, const QPixmap &pix,
+ const QString &text, const QString &a_path) : QListBoxPixmap(listbox, pix, text),
+ path(a_path)
+{
+}
+
+PathListBoxItem::~PathListBoxItem()
+{
+}
diff --git a/kkbswitch/pathlistboxitem.h b/kkbswitch/pathlistboxitem.h
new file mode 100644
index 0000000..590969f
--- /dev/null
+++ b/kkbswitch/pathlistboxitem.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ pathlistboxitem.h - description
+ -------------------
+ begin : ??? ??? 17 2004
+ copyright : (C) 2004 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef PATHLISTBOXITEM_H
+#define PATHLISTBOXITEM_H
+
+#include <qlistbox.h>
+#include <qstring.h>
+
+/**
+ *@author Leonid Zeitlin
+ */
+
+class PathListBoxItem : public QListBoxPixmap {
+public:
+ QString path;
+ PathListBoxItem(QListBox *listbox, const QPixmap &pix, const QString &text,
+ const QString &a_path);
+ ~PathListBoxItem();
+};
+
+#endif
diff --git a/kkbswitch/ru_ua b/kkbswitch/ru_ua
new file mode 100644
index 0000000..4e9d90e
--- /dev/null
+++ b/kkbswitch/ru_ua
@@ -0,0 +1,427 @@
+// Russian + Ukrainian keyboard
+// Based on:
+// russian standard keyboard
+// AEN <aen@logic.ru>
+// Last Changes 2001/12/23 by Leon Kanter <leon@blackcatlinux.com>
+// $XFree86: xc/programs/xkbcomp/symbols/ru,v 3.8 2001/01/17 23:45:59 dawes Exp $
+// and:
+// ukrainian standard keyboard
+// AEN <aen@logic.ru> & Leon Kanter <leon@geon.donetsk.ua>
+// Last Changes 2001/12/11 by Andriy Rysin <arysin@yahoo.com>
+// This keyboard layout has Russian characters at group 2 and Ukrainian
+// at group 3.
+// By Leonid Zeitlin <lz@europe.com>
+// Last Changes 2002/11/09
+
+
+partial default alphanumeric_keys
+xkb_symbols "basic" {
+
+ // Describes the differences between a very simple en_US
+ // keyboard and a very simple Russian keyboard
+
+ name[Group1]= "US/ASCII";
+ name[Group2]= "Russian";
+ name[Group3]= "Ukrainian";
+
+ key <AE01> { [ 1, exclam ],
+ [ 1, exclam ] ,
+ [ 1, exclam ] };
+ key <AE02> { [ 2, at ],
+ [ 2, quotedbl ] ,
+ [ 2, quotedbl ] };
+ key <AE03> { [ 3, numbersign ],
+ [ 3, numbersign ] ,
+ [ 3, numbersign ] };
+ key <AE04> { [ 4, dollar ],
+ [ 4, asterisk ] ,
+ [ 4, asterisk ] };
+ key <AE05> { [ 5, percent ],
+ [ 5, colon ] ,
+ [ 5, colon ] };
+ key <AE06> { [ 6, asciicircum ],
+ [ 6, comma ] ,
+ [ 6, comma ] };
+ key <AE07> { [ 7, ampersand ],
+ [ 7, period ] ,
+ [ 7, period ] };
+ key <AE08> { [ 8, asterisk ],
+ [ 8, semicolon ] ,
+ [ 8, semicolon ] };
+ key <AE09> { [ 9, parenleft ],
+ [ 9, parenleft ] ,
+ [ 9, parenleft ] };
+ key <AE10> { [ 0, parenright ],
+ [ 0, parenright ] ,
+ [ 0, parenright ] };
+ key <AE11> { [ minus, underscore ],
+ [ minus, underscore ] ,
+ [ minus, underscore ] };
+ key <AE12> { [ equal, plus ],
+ [ equal, plus ] ,
+ [ equal, plus ] };
+ key <BKSL> { [ backslash, bar ],
+ [ backslash, bar ] ,
+ [Ukrainian_ghe_with_upturn,Ukrainian_GHE_WITH_UPTURN]};
+ key <AB10> { [ slash, question ],
+ [ slash, question ] ,
+ [ slash, question ] };
+ key <LSGT> { [ less, greater ],
+ [ slash, bar ] ,
+ [ slash, bar ] };
+
+key.type[group2]="ALPHABETIC";
+key.type[group3]="ALPHABETIC";
+
+ key <TLDE> { [ grave, asciitilde ],
+ [ Cyrillic_io, Cyrillic_IO ] ,
+ [ apostrophe, asciitilde ] };
+ key <AD01> { [ q, Q ],
+ [ Cyrillic_shorti, Cyrillic_SHORTI ] ,
+ [ Cyrillic_shorti, Cyrillic_SHORTI ] };
+ key <AD02> { [ w, W ],
+ [ Cyrillic_tse, Cyrillic_TSE ] ,
+ [ Cyrillic_tse, Cyrillic_TSE ] };
+ key <AD03> { [ e, E ],
+ [ Cyrillic_u, Cyrillic_U ] ,
+ [ Cyrillic_u, Cyrillic_U ] };
+ key <AD04> { [ r, R ],
+ [ Cyrillic_ka, Cyrillic_KA ] ,
+ [ Cyrillic_ka, Cyrillic_KA ] };
+ key <AD05> { [ t, T ],
+ [ Cyrillic_ie, Cyrillic_IE ] ,
+ [ Cyrillic_ie, Cyrillic_IE ] };
+ key <AD06> { [ y, Y ],
+ [ Cyrillic_en, Cyrillic_EN ] ,
+ [ Cyrillic_en, Cyrillic_EN ] };
+ key <AD07> { [ u, U ],
+ [ Cyrillic_ghe, Cyrillic_GHE ] ,
+ [ Cyrillic_ghe, Cyrillic_GHE ] };
+ key <AD08> { [ i, I ],
+ [ Cyrillic_sha, Cyrillic_SHA ] ,
+ [ Cyrillic_sha, Cyrillic_SHA ] };
+ key <AD09> { [ o, O ],
+ [ Cyrillic_shcha, Cyrillic_SHCHA ] ,
+ [ Cyrillic_shcha, Cyrillic_SHCHA ] };
+ key <AD10> { [ p, P ],
+ [ Cyrillic_ze, Cyrillic_ZE ] ,
+ [ Cyrillic_ze, Cyrillic_ZE ] };
+ key <AD11> { [ bracketleft, braceleft ],
+ [ Cyrillic_ha, Cyrillic_HA ] ,
+ [ Cyrillic_ha, Cyrillic_HA ] };
+ key <AD12> { [ bracketright, braceright ],
+ [Cyrillic_hardsign,Cyrillic_HARDSIGN ] ,
+ [ Ukrainian_yi, Ukrainian_YI ] };
+ key <AC01> { [ a, A ],
+ [ Cyrillic_ef, Cyrillic_EF ] ,
+ [ Cyrillic_ef, Cyrillic_EF ] };
+ key <AC02> { [ s, S ],
+ [ Cyrillic_yeru, Cyrillic_YERU ] ,
+ [ Ukrainian_i, Ukrainian_I ] };
+ key <AC03> { [ d, D ],
+ [ Cyrillic_ve, Cyrillic_VE ] ,
+ [ Cyrillic_ve, Cyrillic_VE ] };
+ key <AC04> { [ f, F ],
+ [ Cyrillic_a, Cyrillic_A ] ,
+ [ Cyrillic_a, Cyrillic_A ] };
+ key <AC05> { [ g, G ],
+ [ Cyrillic_pe, Cyrillic_PE ] ,
+ [ Cyrillic_pe, Cyrillic_PE ] };
+ key <AC06> { [ h, H ],
+ [ Cyrillic_er, Cyrillic_ER ] ,
+ [ Cyrillic_er, Cyrillic_ER ] };
+ key <AC07> { [ j, J ],
+ [ Cyrillic_o, Cyrillic_O ] ,
+ [ Cyrillic_o, Cyrillic_O ] };
+ key <AC08> { [ k, K ],
+ [ Cyrillic_el, Cyrillic_EL ] ,
+ [ Cyrillic_el, Cyrillic_EL ] };
+ key <AC09> { [ l, L ],
+ [ Cyrillic_de, Cyrillic_DE ] ,
+ [ Cyrillic_de, Cyrillic_DE ] };
+ key <AC10> { [ semicolon, colon ],
+ [ Cyrillic_zhe, Cyrillic_ZHE ] ,
+ [ Cyrillic_zhe, Cyrillic_ZHE ] };
+ key <AC11> { [ apostrophe, quotedbl ],
+ [ Cyrillic_e, Cyrillic_E ] ,
+ [ Ukrainian_ie, Ukrainian_IE ] };
+ key <AB01> { [ z, Z ],
+ [ Cyrillic_ya, Cyrillic_YA ] ,
+ [ Cyrillic_ya, Cyrillic_YA ] };
+ key <AB02> { [ x, X ],
+ [ Cyrillic_che, Cyrillic_CHE ] ,
+ [ Cyrillic_che, Cyrillic_CHE ] };
+ key <AB03> { [ c, C ],
+ [ Cyrillic_es, Cyrillic_ES ] ,
+ [ Cyrillic_es, Cyrillic_ES ] };
+ key <AB04> { [ v, V ],
+ [ Cyrillic_em, Cyrillic_EM ] ,
+ [ Cyrillic_em, Cyrillic_EM ] };
+ key <AB06> { [ n, N ],
+ [ Cyrillic_te, Cyrillic_TE ] ,
+ [ Cyrillic_te, Cyrillic_TE ] };
+ key <AB05> { [ b, B ],
+ [ Cyrillic_i, Cyrillic_I ] ,
+ [ Cyrillic_i, Cyrillic_I ] };
+ key <AB07> { [ m, M ],
+ [Cyrillic_softsign,Cyrillic_SOFTSIGN ] ,
+ [Cyrillic_softsign,Cyrillic_SOFTSIGN ] };
+ key <AB08> { [ comma, less ],
+ [ Cyrillic_be, Cyrillic_BE ] ,
+ [ Cyrillic_be, Cyrillic_BE ] };
+ key <AB09> { [ period, greater ],
+ [ Cyrillic_yu, Cyrillic_YU ] ,
+ [ Cyrillic_yu, Cyrillic_YU ] };
+
+key.type[group2]="TWO_LEVEL";
+key.type[group3]="TWO_LEVEL";
+
+ // End alphanumeric section
+
+ // Begin modifier mappings
+
+ modifier_map Shift { Shift_L };
+ modifier_map Lock { Caps_Lock, ISO_Lock };
+ modifier_map Control{ Control_L };
+ modifier_map Mod3 { Mode_switch };
+};
+
+partial alphanumeric_keys
+xkb_symbols "winkeys" {
+ include "ru_ua(basic)"
+ key <AE03> { [ 3, numbersign ],
+ [ 3, numerosign ] ,
+ [ 3, numerosign ] };
+ key <AE04> { [ 4, dollar ],
+ [ 4, semicolon ] ,
+ [ 4, semicolon ] };
+ key <AE05> { [ 5, percent ],
+ [ 5, percent ] ,
+ [ 5, percent ] };
+ key <AE06> { [ 6, asciicircum ],
+ [ 6, colon ] ,
+ [ 6, colon ] };
+ key <AE07> { [ 7, ampersand ],
+ [ 7, question ] ,
+ [ 7, question ] };
+ key <AE08> { [ 8, asterisk ],
+ [ 8, asterisk ] ,
+ [ 8, asterisk ] };
+ key <AB10> { [ slash, question ],
+ [ period, comma ] ,
+ [ period, comma ] };
+};
+
+partial alphanumeric_keys
+xkb_symbols "typewriter" {
+ include "ru_ua(basic)"
+ key <TLDE> { [ grave, asciitilde ],
+ [ apostrophe, quotedbl ] ,
+ [ apostrophe, quotedbl ] };
+ key <AE01> { [ 1, exclam ],
+ [ exclam, 1 ] ,
+ [ exclam, 1 ] };
+ key <AE02> { [ 2, at ],
+ [ numerosign, 2 ] ,
+ [ numerosign, 2 ] };
+ key <AE03> { [ 3, numbersign ],
+ [ slash, 3 ] ,
+ [ slash, 3 ] };
+ key <AE04> { [ 4, dollar ],
+ [ semicolon, 4 ] ,
+ [ semicolon, 4 ] };
+ key <AE05> { [ 5, percent ],
+ [ colon, 5 ] ,
+ [ colon, 5 ] };
+ key <AE06> { [ 6, asciicircum ],
+ [ comma, 6 ] ,
+ [ comma, 6 ] };
+ key <AE07> { [ 7, ampersand ],
+ [ period, 7 ] ,
+ [ period, 7 ] };
+ key <AE08> { [ 8, asterisk ],
+ [ underscore, 8 ] ,
+ [ underscore, 8 ] };
+ key <AE09> { [ 9, parenleft ],
+ [ question, 9 ] ,
+ [ question, 9 ] };
+ key <AE10> { [ 0, parenright ],
+ [ percent, 0 ] ,
+ [ percent, 0 ] };
+ key <BKSL> { [ backslash, bar ],
+ [ parenleft, parenright ] ,
+ [ parenleft, parenright ] };
+
+key.type[group2]="ALPHABETIC";
+key.type[group3]="ALPHABETIC";
+
+ key <AD12> { [ bracketright, braceright ],
+ [Cyrillic_hardsign,Cyrillic_HARDSIGN ] ,
+ [Ukrainian_yi, Ukrainian_YI ] };
+ key <AB05> { [ b, B ],
+ [ Cyrillic_i, Cyrillic_I ] ,
+ [ Cyrillic_i, Cyrillic_I ] };
+ key <AB10> { [ slash, question ],
+ [ Cyrillic_io, Cyrillic_IO ] ,
+ [ Cyrillic_io, Cyrillic_IO ] };
+};
+
+partial alphanumeric_keys
+xkb_symbols "phonetic" {
+ include "ru_ua(basic)"
+
+ key <AE01> { [ 1, exclam ],
+ [ 1, exclam ] ,
+ [ 1, exclam ] };
+ key <AE02> { [ 2, at ],
+ [ 2, at ] ,
+ [ 2, at ] };
+ key <AE03> { [ 3, numbersign ],
+ [ 3, Cyrillic_io ] ,
+ [ 3, Cyrillic_io ] };
+ key <AE04> { [ 4, dollar ],
+ [ 4, Cyrillic_IO ] ,
+ [ 4, Cyrillic_IO ] };
+ key <AE05> { [ 5, percent ],
+ [ 5, percent ] ,
+ [ 5, percent ] };
+ key <AE06> { [ 6, asciicircum ],
+ [ 6, asciicircum ] ,
+ [ 6, asciicircum ] };
+ key <AE07> { [ 7, ampersand ],
+ [ 7, ampersand ] ,
+ [ 7, ampersand ] };
+ key <AE08> { [ 8, asterisk ],
+ [ 8, asterisk ] ,
+ [ 8, asterisk ] };
+ key <AE09> { [ 9, parenleft ],
+ [ 9, parenleft ] ,
+ [ 9, parenleft ] };
+ key <AE10> { [ 0, parenright ],
+ [ 0, parenright ] ,
+ [ 0, parenright ] };
+
+ key <AB09> { [ period, greater ],
+ [ period, greater ] ,
+ [ period, greater ] };
+ key <AB10> { [ slash, question ],
+ [ slash, question ] ,
+ [ slash, question ] };
+ key <AB08> { [ comma, less ],
+ [ comma, less ] ,
+ [ comma, less ] };
+ key <AC10> { [ semicolon, colon ],
+ [ semicolon, colon ] ,
+ [ semicolon, colon ] };
+ key <AC11> { [ apostrophe, quotedbl ],
+ [ apostrophe, quotedbl ] ,
+ [ apostrophe, quotedbl ] };
+ key <LSGT> { [ less, greater ],
+ [ bar, brokenbar ] ,
+ [ bar, brokenbar ] };
+
+key.type[group2]="ALPHABETIC";
+key.type[group2]="ALPHABETIC";
+
+ key <TLDE> { [ grave, asciitilde ],
+ [ Cyrillic_yu, Cyrillic_YU ] ,
+ [ Cyrillic_yu, Cyrillic_YU ] };
+ key <AD01> { [ q, Q ],
+ [ Cyrillic_ya, Cyrillic_YA ] ,
+ [ Cyrillic_ya, Cyrillic_YA ] };
+ key <AB01> { [ z, Z ],
+ [ Cyrillic_ze, Cyrillic_ZE ] ,
+ [ Cyrillic_ze, Cyrillic_ZE ] };
+ key <AC02> { [ s, S ],
+ [ Cyrillic_es, Cyrillic_ES ] ,
+ [ Cyrillic_es, Cyrillic_ES ] };
+ key <AC01> { [ a, A ],
+ [ Cyrillic_a, Cyrillic_A ] ,
+ [ Cyrillic_a, Cyrillic_A ] };
+ key <AD02> { [ w, W ],
+ [ Cyrillic_ve, Cyrillic_VE ] ,
+ [ Cyrillic_ve, Cyrillic_VE ] };
+ key <AB03> { [ c, C ],
+ [ Cyrillic_tse, Cyrillic_TSE ] ,
+ [ Cyrillic_tse, Cyrillic_TSE ] };
+ key <AB02> { [ x, X ],
+ [Cyrillic_softsign,Cyrillic_SOFTSIGN ] ,
+ [Cyrillic_softsign,Cyrillic_SOFTSIGN ] };
+ key <AC03> { [ d, D ],
+ [ Cyrillic_de, Cyrillic_DE ] ,
+ [ Cyrillic_de, Cyrillic_DE ] };
+ key <AD03> { [ e, E ],
+ [ Cyrillic_ie, Cyrillic_IE ] ,
+ [ Cyrillic_ie, Cyrillic_IE ] };
+ key <AB04> { [ v, V ],
+ [ Cyrillic_zhe, Cyrillic_ZHE ] ,
+ [ Cyrillic_zhe, Cyrillic_ZHE ] };
+ key <AC04> { [ f, F ],
+ [ Cyrillic_ef, Cyrillic_EF ] ,
+ [ Cyrillic_ef, Cyrillic_EF ] };
+ key <AD05> { [ t, T ],
+ [ Cyrillic_te, Cyrillic_TE ] ,
+ [ Cyrillic_te, Cyrillic_TE ] };
+ key <AD04> { [ r, R ],
+ [ Cyrillic_er, Cyrillic_ER ] ,
+ [ Cyrillic_er, Cyrillic_ER ] };
+ key <AB06> { [ n, N ],
+ [ Cyrillic_en, Cyrillic_EN ] ,
+ [ Cyrillic_en, Cyrillic_EN ] };
+ key <AB05> { [ b, B ],
+ [ Cyrillic_be, Cyrillic_BE ] ,
+ [ Cyrillic_be, Cyrillic_BE ] };
+ key <AC06> { [ h, H ],
+ [ Cyrillic_ha, Cyrillic_HA ] ,
+ [ Cyrillic_ha, Cyrillic_HA ] };
+ key <AC05> { [ g, G ],
+ [ Cyrillic_ghe, Cyrillic_GHE ] ,
+ [ Cyrillic_ghe, Cyrillic_GHE ] };
+ key <AD06> { [ y, Y ],
+ [ Cyrillic_yeru, Cyrillic_YERU ] ,
+ [ Cyrillic_yeru, Cyrillic_YERU ] };
+ key <AB07> { [ m, M ],
+ [ Cyrillic_em, Cyrillic_EM ] ,
+ [ Cyrillic_em, Cyrillic_EM ] };
+ key <AC07> { [ j, J ],
+ [ Cyrillic_shorti, Cyrillic_SHORTI ] ,
+ [ Cyrillic_shorti, Cyrillic_SHORTI ] };
+ key <AD07> { [ u, U ],
+ [ Cyrillic_u, Cyrillic_U ] ,
+ [ Cyrillic_u, Cyrillic_U ] };
+ key <AC08> { [ k, K ],
+ [ Cyrillic_ka, Cyrillic_KA ] ,
+ [ Cyrillic_ka, Cyrillic_KA ] };
+ key <AD08> { [ i, I ],
+ [ Cyrillic_i, Cyrillic_I ] ,
+ [ Cyrillic_i, Cyrillic_I ] };
+ key <AD09> { [ o, O ],
+ [ Cyrillic_o, Cyrillic_O ] ,
+ [ Cyrillic_o, Cyrillic_O ] };
+ key <AC09> { [ l, L ],
+ [ Cyrillic_el, Cyrillic_EL ] ,
+ [ Cyrillic_el, Cyrillic_EL ] };
+ key <AD10> { [ p, P ],
+ [ Cyrillic_pe, Cyrillic_PE ] ,
+ [ Cyrillic_pe, Cyrillic_PE ] };
+ key <AE11> { [ minus, underscore ],
+ [ minus, Cyrillic_hardsign ] ,
+ [ minus, Cyrillic_hardsign ] };
+ key <AD11> { [ bracketleft, braceleft ],
+ [ Cyrillic_sha, Cyrillic_SHA ] ,
+ [ Cyrillic_sha, Cyrillic_SHA ] };
+ key <AE12> { [ equal, plus ],
+ [ Cyrillic_che, Cyrillic_CHE ] ,
+ [ Cyrillic_che, Cyrillic_CHE ] };
+ key <AD12> { [ bracketright, braceright ],
+ [ Cyrillic_shcha, Cyrillic_SHCHA ] ,
+ [ Cyrillic_shcha, Cyrillic_SHCHA ] };
+ key <BKSL> { [ backslash, bar ],
+ [ Cyrillic_e, Cyrillic_E ] ,
+ [ Cyrillic_e, Cyrillic_E ] };
+
+ modifier_map Shift { Shift_L };
+ modifier_map Lock { Caps_Lock, ISO_Lock };
+ modifier_map Control{ Control_L };
+ modifier_map Mod3 { Mode_switch };
+};
diff --git a/kkbswitch/singlewindowwatcher.cpp b/kkbswitch/singlewindowwatcher.cpp
new file mode 100644
index 0000000..67a92ce
--- /dev/null
+++ b/kkbswitch/singlewindowwatcher.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "singlewindowwatcher.h"
+#include "kbconfig.h"
+
+#include <kwinmodule.h>
+#include <kdebug.h>
+
+SingleWindowWatcher::SingleWindowWatcher(KBConfig *kbconf, QObject *parent, const char *name)
+ : WindowWatcher(kbconf, parent, name)
+{
+ reset();
+}
+
+SingleWindowWatcher::~SingleWindowWatcher()
+{
+}
+
+void SingleWindowWatcher::windowRemoved(WId id)
+{
+ m_window_map.remove(id);
+}
+
+void SingleWindowWatcher::activeWindowChanged(WId id)
+{
+ if (id == 0) return; // no window is active
+ m_active_window = m_window_map.find(id);
+ if (m_active_window == m_window_map.end())
+ addWindowToMap(id);
+ emit windowChanged(m_active_window.data().groupno, m_active_window.data().next_groupno);
+}
+
+void SingleWindowWatcher::addWindowToMap(WId window_id)
+{
+ KBWinInfo wininfo = { m_kbconf->default_groupno(),
+ m_kbconf->getNextGroup(m_kbconf->default_groupno()) };
+
+ m_active_window = m_window_map.insert(window_id, wininfo);
+}
+
+void SingleWindowWatcher::changeGroup(int groupno, int next_groupno)
+{
+ if (m_active_window != m_window_map.end()) {
+ m_active_window.data().groupno = groupno;
+ m_active_window.data().next_groupno = next_groupno;
+ }
+}
+
+void SingleWindowWatcher::reset()
+{
+ m_window_map.clear();
+ WId active_window = m_kwin_module->activeWindow();
+ if (active_window)
+ addWindowToMap(active_window);
+ else m_active_window = m_window_map.end();
+}
diff --git a/kkbswitch/singlewindowwatcher.h b/kkbswitch/singlewindowwatcher.h
new file mode 100644
index 0000000..8ca717a
--- /dev/null
+++ b/kkbswitch/singlewindowwatcher.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef SINGLEWINDOWWATCHER_H
+#define SINGLEWINDOWWATCHER_H
+
+#include "windowwatcher.h"
+#include <qmap.h>
+
+/**
+Watches for changes of active window and keep a group per each window
+
+@author Leonid Zeitlin
+*/
+class SingleWindowWatcher : public WindowWatcher {
+ Q_OBJECT
+private:
+ struct KBWinInfo {
+ int groupno;
+ int next_groupno;
+ };
+ typedef QMap<WId, KBWinInfo> KBWindowMap;
+ KBWindowMap m_window_map;
+ KBWindowMap::iterator m_active_window;
+ void addWindowToMap(WId window_id);
+protected:
+ virtual void windowAdded(WId /* id */) { /* do nothing */ }
+ virtual void windowRemoved(WId id);
+ virtual void activeWindowChanged(WId id);
+public:
+ SingleWindowWatcher(KBConfig *kbconf, QObject *parent = 0, const char *name = 0);
+ ~SingleWindowWatcher();
+ virtual void changeGroup(int groupno, int next_groupno);
+ virtual void reset();
+};
+
+#endif
diff --git a/kkbswitch/windowclasswatcher.cpp b/kkbswitch/windowclasswatcher.cpp
new file mode 100644
index 0000000..b88e781
--- /dev/null
+++ b/kkbswitch/windowclasswatcher.cpp
@@ -0,0 +1,106 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "windowclasswatcher.h"
+#include "kbconfig.h"
+
+#include <kwinmodule.h>
+#include <kdebug.h>
+
+#include <X11/Xutil.h>
+
+WindowClassWatcher::WindowClassWatcher(KBConfig *kbconf, QObject *parent, const char *name)
+ : WindowWatcher(kbconf, parent, name)
+{
+ reset();
+}
+
+WindowClassWatcher::~WindowClassWatcher()
+{
+}
+
+QString WindowClassWatcher::getWindowClass(WId id)
+{
+ XClassHint hint;
+ QString ret = QString::null;
+
+ if (XGetClassHint(qt_xdisplay(), id, &hint)) {
+ ret = hint.res_class;
+ XFree(hint.res_name);
+ XFree(hint.res_class);
+ }
+ return ret;
+}
+
+void WindowClassWatcher::windowAdded(WId id)
+{
+ QString wclass = getWindowClass(id);
+ KBClassInfo &info = m_class_group_map[wclass];
+ if (info.refcount == 0) {
+ // new class
+ info.groupno = m_kbconf->default_groupno();
+ info.next_groupno = m_kbconf->getNextGroup(m_kbconf->default_groupno());
+ }
+ info.refcount++;
+ m_win_class_map.insert(id, wclass);
+}
+
+void WindowClassWatcher::windowRemoved(WId id)
+{
+ ClassGroupMap::Iterator iter = m_class_group_map.find(m_win_class_map[id]);
+ if (iter != m_class_group_map.end()) {
+ iter.data().refcount--;
+ if (iter.data().refcount <= 0) m_class_group_map.remove(iter);
+ }
+ m_win_class_map.remove(id);
+}
+
+void WindowClassWatcher::activeWindowChanged(WId id)
+{
+ if (id == 0) return; // no window is active
+ m_active_class = m_class_group_map.find(m_win_class_map[id]);
+ if (m_active_class != m_class_group_map.end())
+ emit windowChanged(m_active_class.data().groupno, m_active_class.data().next_groupno);
+}
+
+void WindowClassWatcher::changeGroup(int groupno, int next_groupno)
+{
+ if (m_active_class != m_class_group_map.end()) {
+ m_active_class.data().groupno = groupno;
+ m_active_class.data().next_groupno = next_groupno;
+ }
+}
+
+void WindowClassWatcher::reset()
+{
+ m_win_class_map.clear();
+ m_class_group_map.clear();
+
+ // fill the map with existing windows
+ const QValueList<WId> windows = m_kwin_module->windows();
+ const QValueList<WId>::ConstIterator end = windows.end();
+ for (QValueList<WId>::ConstIterator it = windows.begin(); it != end; ++it)
+ windowAdded(*it);
+
+ WId active_window = m_kwin_module->activeWindow();
+ if (active_window)
+ m_active_class = m_class_group_map.find(m_win_class_map[active_window]);
+ else m_active_class = m_class_group_map.end();
+}
+
diff --git a/kkbswitch/windowclasswatcher.h b/kkbswitch/windowclasswatcher.h
new file mode 100644
index 0000000..5479dd5
--- /dev/null
+++ b/kkbswitch/windowclasswatcher.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef WINDOWCLASSWATCHER_H
+#define WINDOWCLASSWATCHER_H
+
+#include "windowwatcher.h"
+#include <qmap.h>
+
+class QString;
+
+/**
+This class watcher for active window changes and keeps a group per window class
+
+@author Leonid Zeitlin
+*/
+class WindowClassWatcher : public WindowWatcher {
+ Q_OBJECT
+private:
+ typedef QMap<WId, QString> WinClassMap;
+ WinClassMap m_win_class_map;
+ struct KBClassInfo {
+ int groupno;
+ int next_groupno;
+ int refcount;
+ KBClassInfo() : refcount(0) {}
+ };
+ typedef QMap<QString, KBClassInfo> ClassGroupMap;
+ ClassGroupMap m_class_group_map;
+ ClassGroupMap::Iterator m_active_class;
+ QString getWindowClass(WId id);
+protected:
+ virtual void windowAdded(WId id);
+ virtual void windowRemoved(WId id);
+ virtual void activeWindowChanged(WId id);
+public:
+ WindowClassWatcher(KBConfig *kbconf, QObject *parent = 0, const char *name = 0);
+ ~WindowClassWatcher();
+ virtual void changeGroup(int groupno, int next_groupno);
+ virtual void reset();
+};
+
+#endif
diff --git a/kkbswitch/windowwatcher.cpp b/kkbswitch/windowwatcher.cpp
new file mode 100644
index 0000000..821b82c
--- /dev/null
+++ b/kkbswitch/windowwatcher.cpp
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "windowwatcher.h"
+
+#include <kwinmodule.h>
+
+WindowWatcher::WindowWatcher(KBConfig *kbconf, QObject *parent, const char *name)
+ : QObject(parent, name)
+{
+ m_kbconf = kbconf;
+ m_kwin_module = new KWinModule(this);
+ connect(m_kwin_module, SIGNAL(windowAdded(WId)), SLOT(windowAdded(WId)));
+ connect(m_kwin_module, SIGNAL(windowRemoved(WId)), SLOT(windowRemoved(WId)));
+ connect(m_kwin_module, SIGNAL(activeWindowChanged(WId)), SLOT(activeWindowChanged(WId)));
+}
+
+WindowWatcher::~WindowWatcher()
+{
+}
+
diff --git a/kkbswitch/windowwatcher.h b/kkbswitch/windowwatcher.h
new file mode 100644
index 0000000..cb0c835
--- /dev/null
+++ b/kkbswitch/windowwatcher.h
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Leonid Zeitlin *
+ * lz@europe.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+ /* Created 04.05.2004 */
+
+#ifndef WINDOWWATCHER_H
+#define WINDOWWATCHER_H
+
+#include <qobject.h>
+
+class KBConfig;
+class KWinModule;
+
+/**
+@author Leonid Zeitlin
+This class watches for active window changes and notifies KKBSwitch
+that the keyboard group needs to be canged
+*/
+class WindowWatcher : public QObject {
+ Q_OBJECT
+protected:
+ KBConfig *m_kbconf;
+ KWinModule *m_kwin_module;
+protected slots:
+ virtual void windowAdded(WId id) = 0;
+ virtual void windowRemoved(WId id) = 0;
+ virtual void activeWindowChanged(WId id) = 0;
+public:
+ WindowWatcher(KBConfig *kbconf, QObject *parent = 0, const char *name = 0);
+ ~WindowWatcher();
+ virtual void changeGroup(int groupno, int next_groupno) = 0;
+ virtual void reset() = 0;
+signals:
+ void windowChanged(int groupno, int next_groupno);
+};
+
+#endif
diff --git a/kkbswitch/xkeyboard.cpp b/kkbswitch/xkeyboard.cpp
new file mode 100644
index 0000000..085abbf
--- /dev/null
+++ b/kkbswitch/xkeyboard.cpp
@@ -0,0 +1,246 @@
+/***************************************************************************
+ xkeyboard.cpp - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "xkeyboard.h"
+
+#include <qwindowdefs.h>
+#include <qstringlist.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+XKeyboard *XKeyboard::m_self = 0;
+
+XKeyboard::XKeyboard()
+{
+ Display *display = qt_xdisplay();
+#ifdef HAVE_LIBXKLAVIER
+// XklSetDebugLevel(0);
+ XklSetLogAppender(XklLogAppender);
+ XklInit(display);
+ XklRegisterStateCallback(XklStateCallback, this);
+ XklRegisterConfigCallback(XklConfigCallback, this);
+#else
+ int opcode, errorBase, major = XkbMajorVersion, minor = XkbMinorVersion;
+
+ // check the library version
+ if (!XkbLibraryVersion(&major, &minor)) {
+ kdWarning() << i18n("This program was built against XKB extension library\n"
+ "version %1.%2, but is run with the library version %3.%4.\n"
+ "This may cause various problems and even result in a complete\n"
+ "failure to function\n").arg(XkbMajorVersion).arg(XkbMinorVersion).arg(major).arg(minor);
+ }
+
+ // initialize the extension
+ m_xkb_available = XkbQueryExtension(display, &opcode, &m_event_code, &errorBase, &major, &minor);
+ if (!m_xkb_available) {
+ kdError() << i18n("The X Server does not support a compatible XKB extension.\n"
+ "Either the server is not XKB-capable or the extension was disabled.\n"
+ "This program would not work with this server, so it will exit now\n");
+ }
+ else {
+ // register for XKB events
+ //// group state change, i.e. the current group changed:
+ XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotify,
+ XkbAllStateComponentsMask, XkbGroupStateMask);
+ //// keyboard mapping change:
+ XkbSelectEventDetails(display, XkbUseCoreKbd, XkbMapNotify,
+ XkbAllMapComponentsMask, XkbKeySymsMask);
+ //// group names change:
+ XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNamesNotify,
+ XkbAllNamesMask, XkbGroupNamesMask);
+ //// new keyboard:
+ XkbSelectEventDetails(display, XkbUseCoreKbd, XkbNewKeyboardNotify,
+ XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask);
+ // retrieve the number of keyboard groups
+ retrieveNumKbdGroups();
+ }
+#endif
+ m_self = this;
+}
+
+XKeyboard::~XKeyboard(){
+#ifdef HAVE_LIBXKLAVIER
+ XklStopListen();
+ XklTerm();
+#endif
+}
+
+/** Determine if the given XEvent e is an XKB event with type XkbStateNotify.
+ * If so, newgroupno will return the new keyboard group #.
+ * In other words, return value of true means that this XEvent tells us
+ * that the user just switched the keyboard group to the new value
+ * newgroupno */
+/*bool XKeyboard::isXkbStateNotifyEvent(XEvent *e, int *newgroupno){
+ bool ret = false;
+ if (e->type == m_event_code) {
+ XkbEvent *kb_ev = (XkbEvent *) e;
+ if (kb_ev->any.xkb_type == XkbStateNotify) {
+ ret = true;
+ *newgroupno = kb_ev->state.group;
+ }
+ }
+ return ret;
+}*/
+
+/** Set the current keyboard group to the given groupno */
+void XKeyboard::setGroupNo(int groupno){
+#ifdef HAVE_LIBXKLAVIER
+ XklLockGroup(groupno);
+#else
+ XkbLockGroup(qt_xdisplay(), XkbUseCoreKbd, groupno);
+#endif
+}
+
+#ifndef HAVE_LIBXKLAVIER
+extern "C" {
+ static int IgnoreXError(Display *, XErrorEvent *) {
+ return 0;
+ }
+}
+#endif
+
+/** Get the names of the currently configured keyboard groups */
+void XKeyboard::getGroupNames(QStringList &list){
+#ifdef HAVE_LIBXKLAVIER
+ const char** groupnames = XklGetGroupNames();
+ int numgroups = XklGetNumGroups();
+ for (int i = 0; i < numgroups; i++)
+ list.append(groupnames[i]);
+#else
+ XkbDescRec xkb;
+ Display *display = qt_xdisplay();
+ char *names[XkbNumKbdGroups];
+
+ memset(&xkb, 0, sizeof(xkb));
+ xkb.device_spec = XkbUseCoreKbd;
+ XkbGetNames(display, XkbGroupNamesMask, &xkb);
+ memset(names, 0, sizeof(char *) * XkbNumKbdGroups);
+ // XGetAtomNames below may generate BadAtom error, which is not a problem.
+ // (it may happen if the name for a group was not defined)
+ // Thus we temporarily ignore X errors
+ XErrorHandler old_handler = XSetErrorHandler(IgnoreXError);
+ XGetAtomNames(display, xkb.names->groups, m_numgroups, names);
+ // resume normal X error processing
+ XSetErrorHandler(old_handler);
+ for (int i = 0; i < m_numgroups; i++) {
+ if (names[i]) {
+ list.append(names[i]);
+ XFree(names[i]);
+ }
+ else list.append(QString::null);
+ }
+ XkbFreeNames(&xkb, XkbGroupNamesMask, 1);
+#endif
+}
+
+XKeyboard * XKeyboard::self()
+{
+ return m_self;
+}
+
+/** return the current keyboard group index */
+int XKeyboard::getGroupNo(){
+#ifdef HAVE_LIBXKLAVIER
+ return XklGetCurrentState()->group;
+#else
+ XkbStateRec rec;
+ XkbGetState(qt_xdisplay(), XkbUseCoreKbd, &rec);
+ return (int) rec.group;
+#endif
+}
+
+/** Returns if the given event notifies us of a keyboard layout change that requires a
+ * reconfiguration
+ * (e.g. new group added, group names changed, etc.) */
+/*bool XKeyboard::isLayoutChangeEvent(XEvent *e){
+ if (e->type == m_event_code) {
+ XkbEvent *xkb_ev = (XkbEvent *) e;
+ if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
+ || (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
+ || (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
+ retrieveNumKbdGroups();
+ return true;
+ }
+ }
+ return false;
+}*/
+
+#ifndef HAVE_LIBXKLAVIER
+/** No descriptions */
+void XKeyboard::retrieveNumKbdGroups(){
+ XkbDescRec xkb;
+
+ memset(&xkb, 0, sizeof(xkb));
+ /* Interestingly, in RedHat 6.0 (XFree86 3.3.3.1) the XkbGetControls call
+ below works even if xkb.device_spec is not set. But in RedHat 7.1 (XFree86 4.0.3)
+ it returns BadImplementation status code, and you have to specify
+ xkb.device_spec = XkbUseCoreKbd. */
+ xkb.device_spec = XkbUseCoreKbd;
+ XkbGetControls(qt_xdisplay(), XkbGroupsWrapMask, &xkb);
+ m_numgroups = xkb.ctrls->num_groups;
+ XkbFreeControls(&xkb, XkbGroupsWrapMask, 1);
+}
+#endif
+
+/** Examines an X Event passed to it and takes actions if the event is of
+ * interest to XKeyboard */
+void XKeyboard::processEvent(XEvent *ev) {
+#ifdef HAVE_LIBXKLAVIER
+ XklFilterEvents(ev);
+#else
+ if (ev->type == m_event_code) {
+ // This an XKB event
+ XkbEvent *xkb_ev = (XkbEvent *) ev;
+ if (xkb_ev->any.xkb_type == XkbStateNotify) {
+ // state notify event, the current group has changed
+ emit groupChanged(xkb_ev->state.group);
+ }
+ else if ((xkb_ev->any.xkb_type == XkbMapNotify) && (xkb_ev->map.changed & XkbKeySymsMask)
+ || (xkb_ev->any.xkb_type == XkbNamesNotify) && (xkb_ev->names.changed & XkbGroupNamesMask)
+ || (xkb_ev->any.xkb_type == XkbNewKeyboardNotify)) {
+ // keyboard layout has changed
+ retrieveNumKbdGroups();
+ emit layoutChanged();
+ }
+ }
+#endif
+}
+
+#ifdef HAVE_LIBXKLAVIER
+void XKeyboard::XklStateCallback(XklStateChange changeType, int group,
+ Bool /*restore*/, void */*userData*/)
+{
+ if (changeType == GROUP_CHANGED)
+ emit XKeyboard::self()->groupChanged(group);
+}
+
+void XKeyboard::XklConfigCallback(void */*userData*/)
+{
+ emit XKeyboard::self()->layoutChanged();
+}
+
+void XKeyboard::XklLogAppender(const char file[], const char function[],
+ int level, const char format[], va_list args)
+{
+ int size = vsnprintf(NULL, 0, format, args);
+ char *str = new char[size + 1];
+ vsnprintf(str, size, format, args);
+ kdDebug() << file << "/" << function << ": " << str << endl;
+ delete[] str;
+}
+#endif
diff --git a/kkbswitch/xkeyboard.h b/kkbswitch/xkeyboard.h
new file mode 100644
index 0000000..221acb9
--- /dev/null
+++ b/kkbswitch/xkeyboard.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ xkeyboard.h - description
+ -------------------
+ begin : Sun Jul 8 2001
+ copyright : (C) 2001 by Leonid Zeitlin
+ email : lz@europe.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef XKEYBOARD_H
+#define XKEYBOARD_H
+
+#include "config.h"
+
+#include <qobject.h>
+
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#ifdef HAVE_LIBXKLAVIER
+ #include <libxklavier/xklavier.h>
+#endif
+
+class QStringList;
+
+/**This class incapsulates XKeyboard Extension interface
+ *@author Leonid Zeitlin
+ */
+
+class XKeyboard : public QObject {
+ Q_OBJECT
+private:
+#ifndef HAVE_LIBXKLAVIER
+ int m_event_code;
+ int m_numgroups;
+#endif
+ static XKeyboard *m_self;
+ bool m_xkb_available;
+public:
+ static const int MaxNumKbdGroups = XkbNumKbdGroups;
+ XKeyboard();
+ ~XKeyboard();
+ /** Set the current keyboard group to the given groupno */
+ void setGroupNo(int groupno);
+ /** Get the names of the currently configured keyboard groups */
+ void getGroupNames(QStringList &list);
+ static XKeyboard* self();
+ /** return the current keyboard group index */
+ int getGroupNo();
+ /** return if XKEYBOARD extension is available in the X server */
+ bool xkbAvailable() { return m_xkb_available; }
+#ifdef HAVE_LIBXKLAVIER
+ int getNumKbdGroups() { return XklGetNumGroups(); };
+#else
+ int getNumKbdGroups() { return m_numgroups; };
+#endif
+ /** Examines an X Event passed to it and takes actions if the event is of
+ * interest to XKeyboard */
+ void processEvent(XEvent *ev);
+private: // Private methods
+#ifdef HAVE_LIBXKLAVIER
+ static void XklStateCallback(XklStateChange changeType, int group,
+ Bool /*restore*/, void* /*userData*/);
+ static void XklConfigCallback(void */*userData*/);
+ static void XklLogAppender(const char file[], const char function[],
+ int level, const char format[], va_list args);
+#else
+ /** No descriptions */
+ void retrieveNumKbdGroups();
+#endif
+signals: // Signals
+ /** Signals that new keyboard group is selected */
+ void groupChanged(int groupno);
+ /** Signals that keyboard layout has changed and thus we need to reconfigure */
+ void layoutChanged();
+};
+
+#endif