diff options
author | Slávek Banko <slavek.banko@axis.cz> | 2013-08-18 15:43:45 +0200 |
---|---|---|
committer | Slávek Banko <slavek.banko@axis.cz> | 2013-08-18 15:43:45 +0200 |
commit | ae0c828ac29043e7adc56a78fc18d816b32c12b4 (patch) | |
tree | 51cc9b30f40faa951fc029f72c5f5b5e573e863d /kkbswitch | |
download | kkbswitch-ae0c828ac29043e7adc56a78fc18d816b32c12b4.tar.gz kkbswitch-ae0c828ac29043e7adc56a78fc18d816b32c12b4.zip |
Initial import of kkbswitch 1.4.3
Diffstat (limited to 'kkbswitch')
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 ¤tPath, const QPixmap ¤tPixmap, + 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 ¤tPath, + const QPixmap ¤tPixmap) +{ + 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 ¤tPath, const QPixmap ¤tPixmap, + 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 ¤tPath, const QPixmap ¤tPixmap); +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 |