diff --git a/kxkb/CMakeLists.txt b/kxkb/CMakeLists.txt index cb0d4b9db..83ca72be7 100644 --- a/kxkb/CMakeLists.txt +++ b/kxkb/CMakeLists.txt @@ -67,5 +67,5 @@ tde_add_tdeinit_executable( kxkb AUTOMOC extension.cpp x11helper.cpp rules.cpp kxkbconfig.cpp pixmap.cpp layoutmap.cpp kxkb.cpp kxkbtraywindow.cpp kxkb.skel - LINK tdeui-shared ${XKBFILE_LIBRARIES} + LINK tdeui-shared ${XKBFILE_LIBRARIES} ${TDEHW_LIBRARIES} ) diff --git a/kxkb/eventsrc b/kxkb/eventsrc index ce25f3979..1e06d70c3 100644 --- a/kxkb/eventsrc +++ b/kxkb/eventsrc @@ -5,4 +5,9 @@ Comment=TDE Keyboard Tool [LayoutChange] Name=Keyboard layout switch Comment=The keyboard layout was switched +default_presentation=16 + +[Error] +Name=Keyboard layout switching error +Comment=Error while attempting to switch the keyboard layout default_presentation=16 \ No newline at end of file diff --git a/kxkb/extension.cpp b/kxkb/extension.cpp index da0bf73c2..0fada6932 100644 --- a/kxkb/extension.cpp +++ b/kxkb/extension.cpp @@ -1,3 +1,32 @@ +/******************************************************************************* + + Xkb extension for KXkb + Copyright © 2009-2025 Trinity Desktop project + Copyright © 2001 S.R. Haque + + Derived from an original by Matthias H�zer-Klpfel released under the QPL. + + Some portions come from kkbswitch released under the GNU GPL v2 (or later). + Copyright © 2001 Leonid Zeitlin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*******************************************************************************/ + +#include #include #include @@ -5,10 +34,13 @@ #include #include #include +#include #include +#include #include #include +#include #include #include @@ -21,58 +53,77 @@ #include "extension.h" +extern "C" +{ + static int IgnoreXError(Display *, XErrorEvent *) { return 0; } +} static TQString getLayoutKey(const TQString& layout, const TQString& variant) { return layout + "." + variant; } -XKBExtension::XKBExtension(Display *d) +static XKBExtension *xkbExtension = nullptr; + +XKBExtension *XKBExtension::the() { - if ( d == NULL ) - d = tqt_xdisplay(); - m_dpy = d; - -// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" ); -// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0]; - m_tempDir = locateLocal("tmp", ""); + if (!xkbExtension) + { + xkbExtension = new XKBExtension; + if (!xkbExtension->init()) + { + kdFatal() << "xkb initialization failed, exiting..." << endl; + ::exit(1); + } + } + return xkbExtension; } bool XKBExtension::init() { - // Verify the Xlib has matching XKB extension. - - int major = XkbMajorVersion; - int minor = XkbMinorVersion; - - if (!XkbLibraryVersion(&major, &minor)) - { - kdError() << "[kxkb-extension] Xlib XKB extension " << major << '.' << minor << - " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl; - return false; - } - - // Verify the X server has matching XKB extension. - - int opcode_rtrn; - int error_rtrn; - int xkb_opcode; - if (!XkbQueryExtension(m_dpy, &opcode_rtrn, &xkb_opcode, &error_rtrn, - &major, &minor)) - { - kdError() << "[kxkb-extension] X server XKB extension " << major << '.' << minor << - " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl; - return false; - } - - // Do it, or face horrible memory corrupting bugs - ::XkbInitAtoms(NULL); - - // watch group change events - XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify, - XkbAllStateComponentsMask, XkbGroupStateMask); - - return true; + m_configureFilterCounter = 0; + + kdDebug() << "[kxkb-extension] Initializing Xkb extension" << endl; + m_dpy = tqt_xdisplay(); + + // Verify the Xlib has matching XKB extension. + int major = XkbMajorVersion; + int minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) + { + kdError() << "[kxkb-extension] Xlib XKB extension " << major << '.' << minor << + " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl; + return false; + } + + // Verify the X server has matching XKB extension. + int opcode_rtrn; + int error_rtrn; + if (!XkbQueryExtension(m_dpy, &opcode_rtrn, &m_xkb_opcode, &error_rtrn, &major, &minor)) + { + kdError() << "[kxkb-extension] X server XKB extension " << major << '.' << minor << + " != " << XkbMajorVersion << '.' << XkbMinorVersion << endl; + return false; + } + + enableConfigureFilter(); + + // Do it, or face horrible memory corrupting bugs + ::XkbInitAtoms(nullptr); + + // Watch for interesting events + XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbStateNotify, + XkbAllStateComponentsMask, XkbGroupStateMask); + + XkbSelectEventDetails(m_dpy, XkbUseCoreKbd, XkbNewKeyboardNotify, + XkbAllNewKeyboardEventsMask, XkbAllNewKeyboardEventsMask); + + + m_tempDir = locateLocal("tmp", ""); + + disableConfigureFilter(); + return true; } XKBExtension::~XKBExtension() @@ -81,11 +132,32 @@ XKBExtension::~XKBExtension() deletePrecompiledLayouts();*/ } +void XKBExtension::enableConfigureFilter() +{ + ++m_configureFilterCounter; +} + +void XKBExtension::disableConfigureFilter() +{ + // Without this protection in place KXkb would react to configuration + // changes caused by itself + TQTimer::singleShot(500, this, TQ_SLOT(slotReleaseConfigureLock())); +} + +void XKBExtension::slotReleaseConfigureLock() +{ + --m_configureFilterCounter; +} + bool XKBExtension::setXkbOptions(const XkbOptions options) { + enableConfigureFilter(); + TQString exe = TDEGlobal::dirs()->findExe("setxkbmap"); if (exe.isEmpty()) + { return false; + } TDEProcess p; p << exe; @@ -101,7 +173,7 @@ bool XKBExtension::setXkbOptions(const XkbOptions options) p << "-variant"; p << options.variants; } - + if (!options.model.isEmpty()) { p << "-model"; p << options.model; @@ -119,7 +191,8 @@ bool XKBExtension::setXkbOptions(const XkbOptions options) else { // Avoid duplication of options in Append mode - TQStringList srvOptions = TQStringList::split(",", XKBExtension::getServerOptions()); + XkbOptions _opt = getServerOptions(); + TQStringList srvOptions = TQStringList::split(",", _opt.options); TQStringList kxkbOptions = TQStringList::split(",", options.options); TQStringList newOptions; for (TQStringList::Iterator it = kxkbOptions.begin(); it != kxkbOptions.end(); ++it) @@ -136,44 +209,81 @@ bool XKBExtension::setXkbOptions(const XkbOptions options) } } + if (p.args().count() < 2) + { + // Either the user has not configured any Xkb options or these options + // are already set and we are in append mode so we want to avoid + // duplicates + kdWarning() << "[setXkbOptions] No options need to be set" << endl; + slotReleaseConfigureLock(); // immediately release the lock + return true; + } + + p << "-synch"; + kdDebug() << "[setXkbOptions] Command: " << p.args() << endl; p.start(TDEProcess::Block); + disableConfigureFilter(); + return p.normalExit() && (p.exitStatus() == 0); } -TQString XKBExtension::getServerOptions() +XkbOptions XKBExtension::getServerOptions() { - XkbRF_VarDefsRec vd; - if (XkbRF_GetNamesProp(tqt_xdisplay(), nullptr, &vd) && vd.options) - { - kdDebug() << "[kxkb-extension] Got server options " << vd.options << endl; - return TQString(vd.options); - } - return TQString::null; + XkbOptions options; + XkbRF_VarDefsRec vd; + if (XkbRF_GetNamesProp(tqt_xdisplay(), nullptr, &vd)) + { + options.model = vd.model; + options.layouts = vd.layout; + options.variants = vd.variant; + options.options = vd.options; + } + return options; } bool XKBExtension::setGroup(unsigned int group) { kdDebug() << "[kxkb-extension] Setting group " << group << endl; - return XkbLockGroup( m_dpy, XkbUseCoreKbd, group ); + return XkbLockGroup(m_dpy, XkbUseCoreKbd, group); } -unsigned int XKBExtension::getGroup() const +uint XKBExtension::getGroup() const { XkbStateRec xkbState; - XkbGetState( m_dpy, XkbUseCoreKbd, &xkbState ); + XkbGetState(m_dpy, XkbUseCoreKbd, &xkbState); return xkbState.group; } -/** Examines an X Event passed to it and takes actions if the event is of - * interest to KXkb */ +bool XKBExtension::kcmlayoutRunning() +{ + return tdeApp->dcopClient()->isApplicationRegistered("TDECModuleProxy-keyboard_layout"); +} + +// Examines an X Event passed to it and takes actions if the event is of +// interest to KXkb void XKBExtension::processXEvent(XEvent *event) { - XkbEvent* xkb_event = (XkbEvent*)event; - if (xkb_event->any.xkb_type == XkbStateNotify) { - emit groupChanged(xkb_event->state.group); - } + if (event->type == m_xkb_opcode) + { + XkbEvent *xkb_event = (XkbEvent*)event; + if (xkb_event->any.xkb_type == XkbStateNotify && xkb_event->state.changed & XkbGroupStateMask) + { + emit groupChanged((uint)xkb_event->state.group); + } + + else if (xkb_event->any.xkb_type == XkbNewKeyboardNotify) + { + if (m_configureFilterCounter > 0 || kcmlayoutRunning()) + { + return; + } + enableConfigureFilter(); + emit optionsChanged(); + disableConfigureFilter(); + } + } } #include "extension.moc" diff --git a/kxkb/extension.h b/kxkb/extension.h index 9a3d2da8e..e8c9c7d7c 100644 --- a/kxkb/extension.h +++ b/kxkb/extension.h @@ -1,7 +1,36 @@ +/******************************************************************************* + + Xkb extension for KXkb + Copyright © 2009-2025 Trinity Desktop project + Copyright © 2001 S.R. Haque + + Derived from an original by Matthias H�zer-Klpfel released under the QPL. + + Some portions come from kkbswitch released under the GNU GPL v2 (or later). + Copyright © 2001 Leonid Zeitlin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + +*******************************************************************************/ + #ifndef __EXTENSION_H__ #define __EXTENSION_H__ #include + #include #include "kxkbconfig.h" @@ -11,24 +40,44 @@ class XKBExtension : public TQObject TQ_OBJECT public: - XKBExtension(Display *display=NULL); + static XKBExtension *the(); ~XKBExtension(); + + XKBExtension(XKBExtension const&) = delete; + void operator=(XKBExtension const&) = delete; + bool init(); - static bool setXkbOptions(const XkbOptions options); - static TQString getServerOptions(); - bool setGroup(unsigned int group); - unsigned int getGroup() const; + bool setXkbOptions(const XkbOptions options); + bool setGroup(uint group); + + uint getGroup() const; + XkbOptions getServerOptions(); + void processXEvent(XEvent *ev); + void enableConfigureFilter(); + void disableConfigureFilter(); + + bool kcmlayoutRunning(); + +private slots: + void slotReleaseConfigureLock(); + +protected: + XKBExtension() {} + private: - Display *m_dpy; + Display *m_dpy; TQString m_tempDir; int m_keycode; static TQMap fileCache; + int m_configureFilterCounter; + int m_xkb_opcode; signals: void groupChanged(uint group); + void optionsChanged(); }; #endif diff --git a/kxkb/kcmlayout.cpp b/kxkb/kcmlayout.cpp index 70132cd1b..2424a3599 100644 --- a/kxkb/kcmlayout.cpp +++ b/kxkb/kcmlayout.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -107,6 +108,9 @@ LayoutConfig::LayoutConfig(TQWidget *parent, const char *name) m_forceGrpOverwrite(false) { X11Helper::initializeTranslations(); + + m_icoMgr = new LayoutIconManager(&m_kxkbConfig); + TQVBoxLayout *main = new TQVBoxLayout(this, 0, KDialog::spacingHint()); widget = new LayoutConfigWidget(this, "widget"); @@ -143,6 +147,9 @@ LayoutConfig::LayoutConfig(TQWidget *parent, const char *name) connect( widget->grpSwitching, TQ_SIGNAL( clicked( int ) ), TQ_SLOT(changed())); connect( widget->grpLabel, TQ_SIGNAL( clicked( int ) ), TQ_SLOT(changed())); + connect( widget->chkFitToBox, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect( widget->chkDimFlag, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect( widget->bgColor, TQ_SIGNAL( changed(const TQColor&) ), this, TQ_SLOT(changed())); connect( widget->fgColor, TQ_SIGNAL( changed(const TQColor&) ), this, TQ_SLOT(changed())); connect( widget->chkBgTransparent, TQ_SIGNAL( toggled(bool) ), this, TQ_SLOT(changed())); @@ -150,11 +157,14 @@ LayoutConfig::LayoutConfig(TQWidget *parent, const char *name) connect( widget->chkLabelShadow, TQ_SIGNAL( toggled( bool ) ), this, TQ_SLOT(changed())); connect( widget->shColor, TQ_SIGNAL( changed(const TQColor&) ), this, TQ_SLOT(changed())); + connect( widget->chkBevel, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); + connect( widget->chkEnableSticky, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(changed())); connect( widget->spinStickyDepth, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(changed())); connect(widget->chkEnableNotify, TQ_SIGNAL(toggled(bool)), TQ_SLOT(changed())); connect(widget->chkNotifyUseKMilo, TQ_SIGNAL(toggled(bool)), TQ_SLOT(changed())); + connect(widget->chkEnableNotify, TQ_SIGNAL(toggled(bool)), widget->chkNotifyUseKMilo, TQ_SLOT(setEnabled(bool))); widget->listLayoutsSrc->setColumnText(LAYOUT_COLUMN_FLAG, ""); widget->listLayoutsDst->setColumnText(LAYOUT_COLUMN_FLAG, ""); @@ -180,29 +190,39 @@ LayoutConfig::LayoutConfig(TQWidget *parent, const char *name) #define NOSLOTS keys = new TDEGlobalAccel(this); #include "kxkbbindings.cpp" + keys->readSettings(); makeOptionsTab(); - load(); makeShortcutsTab(); + TQTimer::singleShot(0, this, TQ_SLOT(load())); } LayoutConfig::~LayoutConfig() { - delete m_rules; + delete m_rules; + delete m_icoMgr; } void LayoutConfig::load() { - m_kxkbConfig.load(KxkbConfig::LOAD_ALL); + bool modified = false; + m_kxkbConfig.load(KxkbConfig::LOAD_ALL_OPTIONS); - keys->readSettings(); + // Check if the active settings are different from the saved settings + if (m_kxkbConfig.m_useKxkb) + { + XkbOptions options = XKBExtension::the()->getServerOptions(); + modified = m_kxkbConfig.setFromXkbOptions(options); + } - initUI(); + m_kxkbConfig.load(KxkbConfig::LOAD_ALL_OPTIONS); + keys->readSettings(); + initUI(modified); } -void LayoutConfig::initUI() { +void LayoutConfig::initUI(bool modified) { const char* modelName = m_rules->models()[m_kxkbConfig.m_model]; if( modelName == NULL ) modelName = DEFAULT_MODEL; @@ -219,7 +239,6 @@ void LayoutConfig::initUI() { for ( ; src_it.current(); ++src_it ) { TQListViewItem* srcItem = src_it.current(); - if ( layoutUnit.layout == src_it.current()->text(LAYOUT_COLUMN_MAP) ) { // check if current config knows about this layout TQListViewItem* newItem = copyLVI(srcItem, widget->listLayoutsDst); @@ -260,6 +279,8 @@ void LayoutConfig::initUI() { widget->radFlagLabel->setChecked( showFlag && showLabel ); widget->radFlagOnly->setChecked( showFlag && !showLabel ); widget->radLabelOnly->setChecked( !showFlag && showLabel ); + widget->chkFitToBox->setChecked(m_kxkbConfig.m_fitToBox); + widget->chkDimFlag->setChecked(m_kxkbConfig.m_dimFlag); widget->xkbOptsMode->setButton(m_kxkbConfig.m_resetOldOptions ? 0 : 1); @@ -271,11 +292,15 @@ void LayoutConfig::initUI() { widget->chkLabelShadow->setChecked( m_kxkbConfig.m_labelShadow ); widget->shColor->setColor( m_kxkbConfig.m_colorShadow ); + widget->chkBevel->setChecked(m_kxkbConfig.m_bevel); + widget->grpLabel->setDisabled(showFlag && !showLabel); widget->grpLabelColors->setDisabled(m_kxkbConfig.m_useThemeColors); widget->labelBgColor->setDisabled(showFlag); widget->bgColor->setDisabled(showFlag); widget->chkBgTransparent->setDisabled(showFlag); + widget->grpFlag->setEnabled(showFlag); + widget->chkDimFlag->setEnabled(showFlag && showLabel); switch( m_kxkbConfig.m_switchingPolicy ) { default: @@ -296,6 +321,7 @@ void LayoutConfig::initUI() { widget->chkEnableNotify->setChecked(m_kxkbConfig.m_enableNotify); widget->chkNotifyUseKMilo->setChecked(m_kxkbConfig.m_notifyUseKMilo); + widget->chkNotifyUseKMilo->setEnabled(m_kxkbConfig.m_enableNotify); updateStickyLimit(); @@ -341,7 +367,7 @@ void LayoutConfig::initUI() { updateOptionsCommand(); updateHotkeyCombo(true); - emit TDECModule::changed( false ); + emit TDECModule::changed(modified); } @@ -353,6 +379,9 @@ void LayoutConfig::save() m_kxkbConfig.m_resetOldOptions = widget->radXkbOverwrite->isOn(); m_kxkbConfig.m_options = createOptionString(); + m_kxkbConfig.m_fitToBox = widget->chkFitToBox->isChecked(); + m_kxkbConfig.m_dimFlag = widget->chkDimFlag->isChecked(); + m_kxkbConfig.m_useThemeColors = widget->radLabelUseTheme->isChecked(); m_kxkbConfig.m_colorBackground = widget->bgColor->color(); m_kxkbConfig.m_colorLabel = widget->fgColor->color(); @@ -361,6 +390,8 @@ void LayoutConfig::save() m_kxkbConfig.m_labelShadow = widget->chkLabelShadow->isChecked(); m_kxkbConfig.m_colorShadow = widget->shColor->color(); + m_kxkbConfig.m_bevel = widget->chkBevel->isChecked(); + TQListViewItem *item = widget->listLayoutsDst->firstChild(); TQValueList layouts; while (item) { @@ -415,7 +446,8 @@ void LayoutConfig::save() if (m_forceGrpOverwrite) { // First get all the server's options - TQStringList srvOptions = TQStringList::split(",", XKBExtension::getServerOptions()); + XkbOptions _opt = XKBExtension::the()->getServerOptions(); + TQStringList srvOptions = TQStringList::split(",", _opt.options); TQStringList newOptions; // Then remove all grp: options @@ -432,7 +464,7 @@ void LayoutConfig::save() xkbOptions.options = newOptions.join(","); xkbOptions.resetOld = true; - if (!XKBExtension::setXkbOptions(xkbOptions)) + if (!XKBExtension::the()->setXkbOptions(xkbOptions)) { kdWarning() << "[LayoutConfig::save] Could not overwrite previous grp: options!" << endl; } @@ -990,7 +1022,8 @@ void LayoutConfig::updateHotkeyCombo(bool initial) { // Get server options first if (initial || widget->xkbOptsMode->selectedId() == 1) { - TQStringList opts = TQStringList::split(",", XKBExtension::getServerOptions()); + XkbOptions _opt = XKBExtension::the()->getServerOptions(); + TQStringList opts = TQStringList::split(",", _opt.options); for (TQStringList::Iterator it = opts.begin(); it != opts.end(); ++it) { TQString option(*it); @@ -1141,7 +1174,7 @@ void LayoutConfig::loadRules() TQString layoutName = it2.current(); TQListViewItem *item = new TQListViewItem(widget->listLayoutsSrc); - item->setPixmap(LAYOUT_COLUMN_FLAG, LayoutIcon::getInstance().findPixmap(layout, false)); + item->setPixmap(LAYOUT_COLUMN_FLAG, m_icoMgr->find(layout, PIXMAP_STYLE_CONTEXTMENU)); item->setText(LAYOUT_COLUMN_NAME, i18n(layoutName.latin1())); item->setText(LAYOUT_COLUMN_MAP, layout); ++it2; @@ -1250,7 +1283,7 @@ extern "C" tdeApp->startServiceByDesktopName("kxkb"); } else { - if (!XKBExtension::setXkbOptions(m_kxkbConfig.getKXkbOptions())) { + if (!XKBExtension::the()->setXkbOptions(m_kxkbConfig.getKXkbOptions())) { kdDebug() << "Setting XKB options failed!" << endl; } } diff --git a/kxkb/kcmlayout.h b/kxkb/kcmlayout.h index db0f89690..0d2e153b2 100644 --- a/kxkb/kcmlayout.h +++ b/kxkb/kcmlayout.h @@ -11,6 +11,7 @@ class OptionListItem; +class LayoutIconManager; class LayoutConfigWidget; class XkbRules; @@ -22,11 +23,13 @@ public: LayoutConfig(TQWidget *parent = 0L, const char *name = 0L); virtual ~LayoutConfig(); + void initUI(bool modified = false); + virtual TQString handbookDocPath() const; + +public slots: void load(); void save(); void defaults(); - void initUI(); - virtual TQString handbookDocPath() const; protected: TQString createOptionString(); @@ -52,6 +55,7 @@ protected slots: void changed(); private: + LayoutIconManager *m_icoMgr; LayoutConfigWidget* widget; XkbRules *m_rules; diff --git a/kxkb/kcmlayoutwidget.ui b/kxkb/kcmlayoutwidget.ui index 11d147211..52cab2e88 100644 --- a/kxkb/kcmlayoutwidget.ui +++ b/kxkb/kcmlayoutwidget.ui @@ -8,8 +8,8 @@ 0 0 - 709 - 563 + 700 + 600 @@ -22,8 +22,8 @@ - 600 - 510 + 700 + 600 @@ -904,36 +904,19 @@ - - - spacer22 - - - Horizontal - - - Fixed - - - - 20 - 20 - - - - - - chkBgTransparent - - - Transparent background - - - Check this to remove the indicator's background. Only applicable in "Label only" mode. - - + + + chkBgTransparent + + + Transparent background + + + Check this to remove the indicator's background. Only applicable in "Label only" mode. + + separator1 @@ -992,7 +975,8 @@ 0 - + + spacer23 @@ -1011,6 +995,35 @@ + + + grpFlag + + + Flag Style + + + + + chkFitToBox + + + Stretc&h flag + + + If this option is enabled, the flag will be stretched to fit the tray indicator size. + + + + + chkDimFlag + + + Dim flag to make the label more visible + + + + grpMisc @@ -1027,6 +1040,17 @@ Show indicator for single layout + + + chkBevel + + + Show indicator bevel + + + If this option is enabled, the layout indicator will be drawn with a thin 3D bevel around it. + + @@ -1209,8 +1233,8 @@ toggled(bool) bgColor setEnabled(bool) - - + + radLabelOnly toggled(bool) labelBgColor @@ -1234,6 +1258,30 @@ chkNotifyUseKMilo setEnabled(bool) + + radFlagOnly + toggled(bool) + grpFlag + setEnabled(bool) + + + radFlagLabel + toggled(bool) + grpFlag + setEnabled(bool) + + + radLabelOnly + toggled(bool) + grpFlag + setDisabled(bool) + + + radFlagLabel + toggled(bool) + chkDimFlag + setEnabled(bool) + kiconloader.h diff --git a/kxkb/kxkb.cpp b/kxkb/kxkb.cpp index ffde6073a..d62999015 100644 --- a/kxkb/kxkb.cpp +++ b/kxkb/kxkb.cpp @@ -24,16 +24,17 @@ DESCRIPTION */ #include -#include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -64,17 +65,14 @@ DESCRIPTION KXKBApp::KXKBApp(bool allowStyles, bool GUIenabled) : TDEUniqueApplication(allowStyles, GUIenabled), m_prevWinId(X11Helper::UNKNOWN_WINDOW_ID), - m_rules(NULL), - m_tray(NULL), - kWinModule(NULL) + m_rules(nullptr), + m_tray(nullptr), + kWinModule(nullptr) { - X11Helper::initializeTranslations(); - m_extension = new XKBExtension(); - if( !m_extension->init() ) { - kdDebug() << "xkb initialization failed, exiting..." << endl; - ::exit(1); - } - connect(m_extension, TQ_SIGNAL(groupChanged(uint)), this, TQ_SLOT(slotGroupChanged(uint))); + X11Helper::initializeTranslations(); + XKBExtension *xkb = XKBExtension::the(); + connect(xkb, TQ_SIGNAL(groupChanged(uint)), this, TQ_SLOT(slotGroupChanged(uint))); + connect(xkb, TQ_SIGNAL(optionsChanged()), this, TQ_SLOT(slotSyncXkbOptions())); m_layoutOwnerMap = new LayoutMap(kxkbConfig); @@ -84,14 +82,17 @@ KXKBApp::KXKBApp(bool allowStyles, bool GUIenabled) connect( this, TQ_SIGNAL(settingsChanged(int)), TQ_SLOT(slotSettingsChanged(int)) ); addKipcEventMask( KIPC::SettingsChanged ); -} + TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); + connect(hwdevices, TQ_SIGNAL(hardwareAdded(TDEGenericDevice*)), this, TQ_SLOT(hardwareChanged(TDEGenericDevice*))); + connect(hwdevices, TQ_SIGNAL(hardwareRemoved(TDEGenericDevice*)), this, TQ_SLOT(hardwareChanged(TDEGenericDevice*))); + connect(hwdevices, TQ_SIGNAL(hardwareUpdated(TDEGenericDevice*)), this, TQ_SLOT(hardwareChanged(TDEGenericDevice*))); +} KXKBApp::~KXKBApp() { delete m_tray; delete m_rules; - delete m_extension; delete m_layoutOwnerMap; delete kWinModule; delete keys; @@ -99,231 +100,296 @@ KXKBApp::~KXKBApp() int KXKBApp::newInstance() { - if (settingsRead()) { - layoutApply(); - } - + readSettings(); return 0; } -bool KXKBApp::settingsRead() +void KXKBApp::readSettings() { - XkbOptions options = kxkbConfig.getKXkbOptions(); - if( !m_extension->setXkbOptions(options) ) { - kdDebug() << "Setting XKB options failed!" << endl; - } + // Xkb options + kxkbConfig.load(KxkbConfig::LOAD_INIT_OPTIONS); - if ( kxkbConfig.m_useKxkb == false ) { - tdeApp->quit(); - return false; + if (!kxkbConfig.m_useKxkb) + { + kdDebug() << "kxkb is disabled, applying xkb options and exiting" << endl; + applyXkbOptions(); + quit(); + return; } - - m_prevWinId = X11Helper::UNKNOWN_WINDOW_ID; - - if( kxkbConfig.m_switchingPolicy == SWITCH_POLICY_GLOBAL ) { - delete kWinModule; - kWinModule = NULL; - } - else { - TQDesktopWidget desktopWidget; - if( desktopWidget.numScreens() > 1 && desktopWidget.isVirtualDesktop() == false ) { - kdWarning() << "With non-virtual desktop only global switching policy supported on non-primary screens" << endl; - //TODO: find out how to handle that - } - - if( kWinModule == NULL ) { - kWinModule = new KWinModule(0, KWinModule::INFO_DESKTOP); - connect(kWinModule, TQ_SIGNAL(activeWindowChanged(WId)), TQ_SLOT(windowChanged(WId))); - } - m_prevWinId = kWinModule->activeWindow(); - kdDebug() << "Active window " << m_prevWinId << endl; - } - - m_layoutOwnerMap->reset(); - m_layoutOwnerMap->setCurrentWindow( m_prevWinId ); - - if( m_rules == NULL ) - m_rules = new XkbRules(false); - - for(int ii=0; ii<(int)kxkbConfig.m_layouts.count(); ii++) { - LayoutUnit& layoutUnit = kxkbConfig.m_layouts[ii]; - } - - m_currentLayout = kxkbConfig.m_layouts[0]; - kdDebug() << "default layout is " << m_currentLayout.toPair() << endl; - - if( kxkbConfig.m_layouts.count() == 1 && !kxkbConfig.m_showSingle) { - tdeApp->quit(); - return false; - } - - initTray(); - - TDEGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals - keys->readSettings(); - keys->updateConnections(); - - return true; + + kdDebug() << "applying xkb options and layouts" << endl; + kxkbConfig.load(KxkbConfig::LOAD_ALL_OPTIONS); + applyXkbOptions(); + + // Active window watcher + m_prevWinId = X11Helper::UNKNOWN_WINDOW_ID; + + if (kxkbConfig.m_switchingPolicy == SWITCH_POLICY_GLOBAL) + { + delete kWinModule; + kWinModule = nullptr; + } + + else + { + TQDesktopWidget desktopWidget; + if (desktopWidget.numScreens() > 1 && !desktopWidget.isVirtualDesktop()) + { + kdWarning() << "With non-virtual desktop only global switching policy supported on non-primary screens" << endl; + //TODO: find out how to handle that + } + + if (!kWinModule) + { + kWinModule = new KWinModule(nullptr, KWinModule::INFO_DESKTOP); + connect(kWinModule, TQ_SIGNAL(activeWindowChanged(WId)), TQ_SLOT(windowChanged(WId))); + } + + m_prevWinId = kWinModule->activeWindow(); + kdDebug() << "Active window " << m_prevWinId << endl; + } + + // Init layout owner map + m_layoutOwnerMap->reset(); + m_layoutOwnerMap->setCurrentWindow( m_prevWinId ); + + // Init rules + if (!m_rules) + { + m_rules = new XkbRules(false); + } + + // Init layouts + for (int i = 0; i < kxkbConfig.m_layouts.count(); i++) + { + LayoutUnit& layoutUnit = kxkbConfig.m_layouts[i]; + } + + m_currentLayout = kxkbConfig.m_layouts[0]; + setLayout(m_currentLayout); + + kdDebug() << "default layout is " << m_currentLayout.toPair() << endl; + + if (kxkbConfig.m_layouts.count() == 1 && !kxkbConfig.m_showSingle) + { + quit(); + return; + } + + TDEGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals + + // Init tray + if (!m_tray) + { + m_tray = new KxkbSystemTray(&kxkbConfig); + connect(m_tray, TQ_SIGNAL(menuActivated(int)), this, TQ_SLOT(menuActivated(int))); + connect(m_tray, TQ_SIGNAL(toggled()), this, TQ_SLOT(nextLayout())); + } + + m_tray->initLayoutList(kxkbConfig.m_layouts, *m_rules); + m_tray->setCurrentLayout(m_currentLayout); + m_tray->show(); + + // Init keybindings + keys->readSettings(); + keys->updateConnections(); } -void KXKBApp::initTray() +void KXKBApp::applyXkbOptions() { - if( !m_tray ) - { - KSystemTray* sysTray = new KxkbSystemTray(); - TDEPopupMenu* popupMenu = sysTray->contextMenu(); - // popupMenu->insertTitle( tdeApp->miniIcon(), tdeApp->caption() ); - - m_tray = new KxkbLabelController(sysTray, popupMenu); - connect(popupMenu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(menuActivated(int))); - connect(sysTray, TQ_SIGNAL(toggled()), this, TQ_SLOT(nextLayout())); - } - - m_tray->setShowFlag(kxkbConfig.m_showFlag); - m_tray->initLayoutList(kxkbConfig.m_layouts, *m_rules); - m_tray->setCurrentLayout(m_currentLayout); - m_tray->show(); + XkbOptions options = kxkbConfig.getKXkbOptions(); + if (!XKBExtension::the()->setXkbOptions(options)) { + kdWarning() << "Setting XKB options failed!" << endl; + } } -// This function activates the keyboard layout specified by the -// configuration members (m_currentLayout) -void KXKBApp::layoutApply() +void KXKBApp::hardwareChanged(TDEGenericDevice *dev) { - setLayout(m_currentLayout); + if (dev->type() == TDEGenericDeviceType::Keyboard) + { + TQTimer::singleShot(500, this, TQ_SLOT(applyXkbOptions())); + } } // kdcop bool KXKBApp::setLayout(const TQString& layoutPair) { - const LayoutUnit layoutUnitKey(layoutPair); - if( kxkbConfig.m_layouts.contains(layoutUnitKey) ) { - return setLayout( *kxkbConfig.m_layouts.find(layoutUnitKey) ); - } - return false; + return setLayout((LayoutUnit)layoutPair); } // Activates the keyboard layout specified by 'layoutUnit' bool KXKBApp::setLayout(const LayoutUnit& layoutUnit) { - uint group = kxkbConfig.m_layouts.findIndex(layoutUnit); - bool res = m_extension->setGroup(group); - if (res) { - m_currentLayout = layoutUnit; - maybeShowLayoutNotification(); - } - - if (m_tray) { - if (res) { - m_tray->setCurrentLayout(layoutUnit); - } else { - m_tray->setError(layoutUnit.toPair()); - } - } - - return res; + const int group = kxkbConfig.m_layouts.findIndex(layoutUnit); + if (group >= 0) { + return setLayout(group); + } + return false; } + // Activates the keyboard layout specified by group number bool KXKBApp::setLayout(const uint group) { - bool res = m_extension->setGroup(group); - if (res) { - m_currentLayout = kxkbConfig.m_layouts[group]; - } + // If this group is already set, just show the notification and return + if (XKBExtension::the()->getGroup() == group) { + if (kxkbConfig.m_enableNotify) { + showLayoutNotification(); + } + return true; + } - if (m_tray) { - if (res) - m_tray->setCurrentLayout(m_currentLayout); - else - m_tray->setError(m_currentLayout.toPair()); - } + bool ok = XKBExtension::the()->setGroup(group); + if (!ok) { + TQString layout = kxkbConfig.m_layouts[group].toPair(); + if (m_tray) { + m_tray->setError(layout); + } - return res; + if (kxkbConfig.m_enableNotify) { + showErrorNotification(layout); + } + } + return ok; } - void KXKBApp::nextLayout() { - const LayoutUnit& layout = m_layoutOwnerMap->getNextLayout().layoutUnit; - setLayout(layout); + const LayoutUnit& layout = m_layoutOwnerMap->getNextLayout().layoutUnit; + setLayout(layout); } void KXKBApp::prevLayout() { - const LayoutUnit& layout = m_layoutOwnerMap->getPrevLayout().layoutUnit; - setLayout(layout); + const LayoutUnit& layout = m_layoutOwnerMap->getPrevLayout().layoutUnit; + setLayout(layout); } void KXKBApp::menuActivated(int id) { - if( KxkbLabelController::START_MENU_ID <= id - && id < KxkbLabelController::START_MENU_ID + (int)kxkbConfig.m_layouts.count() ) - { - const LayoutUnit& layout = kxkbConfig.m_layouts[id - KxkbLabelController::START_MENU_ID]; - m_layoutOwnerMap->setCurrentLayout( layout ); - setLayout( layout ); - } - else if (id == KxkbLabelController::CONFIG_MENU_ID) + if (id >= KxkbSystemTray::START_MENU_ID && + id < KxkbSystemTray::START_MENU_ID + kxkbConfig.m_layouts.count()) + { + setLayout(id - KxkbSystemTray::START_MENU_ID); + } + else if (id == KxkbSystemTray::CONFIG_MENU_ID) { TDEProcess p; p << "tdecmshell" << "keyboard_layout"; p.start(TDEProcess::DontCare); - } - else if (id == KxkbLabelController::HELP_MENU_ID) - { - tdeApp->invokeHelp(0, "kxkb"); - } -// else -// { -// quit(); -// } + } + else if (id == KxkbSystemTray::HELP_MENU_ID) + { + invokeHelp(0, "kxkb"); + } + else + { + quit(); + } } void KXKBApp::slotGroupChanged(uint group) { - if (group >= kxkbConfig.m_layouts.count()) - { - group = 0; - } - m_currentLayout = kxkbConfig.m_layouts[group]; - m_tray->setCurrentLayout(m_currentLayout); - maybeShowLayoutNotification(); -} + if (!kxkbConfig.m_layouts.count()) { + kdError() << "[kxkb] no layout found!" << endl; + return; + } -void KXKBApp::maybeShowLayoutNotification() { - if (!kxkbConfig.m_enableNotify) return; + if (group >= kxkbConfig.m_layouts.count()) { + kdError() << "[kxkb] unknown group requested: " << group << endl; + if (m_tray) + { + m_tray->setError(i18n("Unknown")); + } + if (kxkbConfig.m_enableNotify) + { + showErrorNotification(i18n("Unknown")); + } + return; + } + + m_currentLayout = kxkbConfig.m_layouts[group]; + m_layoutOwnerMap->setCurrentLayout(m_currentLayout); + + if (m_tray) { + m_tray->setCurrentLayout(m_currentLayout); + } + + if (kxkbConfig.m_enableNotify) { + showLayoutNotification(); + } +} - TQString layoutName(m_rules->getLayoutName(m_currentLayout)); - bool useKMilo = kxkbConfig.m_notifyUseKMilo; - bool notificationSent = false; +void KXKBApp::slotSyncXkbOptions() +{ + // Make sure the X11 server has had enough time to apply the change + TQTimer::singleShot(100, this, TQ_SLOT(syncXkbOptions())); +} - // Query KDED whether KMiloD is loaded - if (useKMilo) { - QCStringList modules; - TQCString replyType; - TQByteArray replyData; - if (tdeApp->dcopClient()->call("kded", "kded", "loadedModules()", - TQByteArray(), replyType, replyData)) +void KXKBApp::syncXkbOptions() +{ + XkbOptions options = XKBExtension::the()->getServerOptions(); + if (kxkbConfig.setFromXkbOptions(options)) + { + m_layoutOwnerMap->reset(); + if (m_tray) { - if (replyType == "QCStringList") { - TQDataStream reply(replyData, IO_ReadOnly); - reply >> modules; - - if (!modules.contains("kmilod")) { - useKMilo = false; - } - } + m_tray->initLayoutList(kxkbConfig.m_layouts, *m_rules); } } + slotGroupChanged(XKBExtension::the()->getGroup()); +} - if (useKMilo) { - DCOPRef kmilo("kded", "kmilod"); - if (kmilo.send("displayText(TQString,TQPixmap)", layoutName, tdeApp->miniIcon())) - notificationSent = true; - } +void KXKBApp::showLayoutNotification() +{ + bool useKMilo = kxkbConfig.m_notifyUseKMilo && isKMiloAvailable(), + notificationSent = false; - if (!notificationSent) { - KNotifyClient::event(m_tray->winId(), "LayoutChange", layoutName); - } + TQString layoutName(m_rules->getLayoutName(m_currentLayout)); + + if (useKMilo) { + DCOPRef kmilo("kded", "kmilod"); + if (kmilo.send("displayText(TQString,TQPixmap)", layoutName, miniIcon())) { + notificationSent = true; + } + } + + if (!notificationSent) { + WId wid = (m_tray ? m_tray->winId() : 0); + KNotifyClient::event(wid, "LayoutChange", layoutName); + } +} + +void KXKBApp::showErrorNotification(TQString layout) { + bool useKMilo = kxkbConfig.m_notifyUseKMilo && isKMiloAvailable(), + notificationSent = false; + + if (useKMilo) { + DCOPRef kmilo("kded", "kmilod"); + if (kmilo.send("displayText(TQString,TQPixmap)", i18n("Error changing keyboard layout to '%1'").arg(layout), miniIcon())) { + notificationSent = true; + } + } + + if (!notificationSent) { + WId wid = (m_tray ? m_tray->winId() : 0); + KNotifyClient::event(wid, "Error"); + } +} + +bool KXKBApp::isKMiloAvailable() { + QCStringList modules; + TQCString replyType; + TQByteArray replyData; + if (dcopClient()->call("kded", "kded", "loadedModules()", + TQByteArray(), replyType, replyData)) + { + if (replyType == "QCStringList") { + TQDataStream reply(replyData, IO_ReadOnly); + reply >> modules; + return modules.contains("kmilod"); + } + } + return false; } // TODO: we also have to handle deleted windows @@ -336,18 +402,18 @@ void KXKBApp::windowChanged(WId winId) } kdDebug() << "old WinId: " << m_prevWinId << ", new WinId: " << winId << endl; - + if( m_prevWinId != X11Helper::UNKNOWN_WINDOW_ID ) { // saving layout from previous window // m_layoutOwnerMap->setCurrentWindow(m_prevWinId); m_layoutOwnerMap->setCurrentLayout(m_currentLayout); } - + m_prevWinId = winId; if( winId != X11Helper::UNKNOWN_WINDOW_ID ) { m_layoutOwnerMap->setCurrentWindow(winId); const LayoutState& layoutState = m_layoutOwnerMap->getCurrentLayout(); - + if( layoutState.layoutUnit != m_currentLayout ) { kdDebug() << "switching to " << layoutState.layoutUnit.toPair() << " for " << winId << endl; setLayout(layoutState.layoutUnit); @@ -355,7 +421,6 @@ void KXKBApp::windowChanged(WId winId) } } - void KXKBApp::slotSettingsChanged(int category) { if (category == TDEApplication::SETTINGS_SHORTCUTS) { @@ -367,7 +432,7 @@ void KXKBApp::slotSettingsChanged(int category) bool KXKBApp::x11EventFilter(XEvent *e) { // let the extension process the event and emit signals if necessary - m_extension->processXEvent(e); + XKBExtension::the()->processXEvent(e); return TDEApplication::x11EventFilter(e); } diff --git a/kxkb/kxkb.h b/kxkb/kxkb.h index c4d5bf334..5cbebed5a 100644 --- a/kxkb/kxkb.h +++ b/kxkb/kxkb.h @@ -32,6 +32,7 @@ DESCRIPTION #include #include +#include #include "kxkbtraywindow.h" #include "kxkbconfig.h" @@ -72,19 +73,23 @@ public slots: protected slots: void menuActivated(int id); void windowChanged(WId winId); - void layoutApply(); void slotGroupChanged(uint group); void slotSettingsChanged(int category); - void maybeShowLayoutNotification(); + void showLayoutNotification(); + void showErrorNotification(TQString layout); -protected: - // Read settings, and apply them. - bool settingsRead(); + void hardwareChanged(TDEGenericDevice *dev); + + void readSettings(); + void applyXkbOptions(); + void slotSyncXkbOptions(); + void syncXkbOptions(); private: void initTray(); bool x11EventFilter(XEvent *e); + bool isKMiloAvailable(); private: KxkbConfig kxkbConfig; @@ -96,7 +101,7 @@ private: XKBExtension *m_extension; XkbRules *m_rules; - KxkbLabelController *m_tray; + KxkbSystemTray *m_tray; TDEGlobalAccel *keys; KWinModule* kWinModule; bool m_forceSetXKBMap; diff --git a/kxkb/kxkbconfig.cpp b/kxkb/kxkbconfig.cpp index 0c3dc9e0a..fd86f049a 100644 --- a/kxkb/kxkbconfig.cpp +++ b/kxkb/kxkbconfig.cpp @@ -30,112 +30,150 @@ static const char* switchModes[SWITCH_POLICY_COUNT] = { const LayoutUnit DEFAULT_LAYOUT_UNIT = LayoutUnit("us", ""); const char* DEFAULT_MODEL = "pc104"; -bool KxkbConfig::load(int loadMode) +void KxkbConfig::load(int loadMode) { + // INITIAL OPTIONS (loaded regardless of whether KXkb is enabled) + TDEConfig *config = new TDEConfig("kxkbrc", true, false); config->setGroup("Layout"); - if( loadMode == LOAD_ALL ) { - m_resetOldOptions = config->readBoolEntry("ResetOldOptions", true); - m_options = config->readEntry("Options", ""); - } - m_useKxkb = config->readBoolEntry("Use", false); - kdDebug() << "Use kxkb " << m_useKxkb << endl; - if( (m_useKxkb == false && loadMode == LOAD_ACTIVE_OPTIONS ) - || loadMode == LOAD_INIT_OPTIONS ) - return true; + m_resetOldOptions = config->readBoolEntry("ResetOldOptions", true); + m_options = config->readEntry("Options", ""); + + if (loadMode == LOAD_INIT_OPTIONS) + { + return; + } + + // BASIC OPTIONS (passed to setxkbmap) m_model = config->readEntry("Model", DEFAULT_MODEL); - kdDebug() << "Model: " << m_model << endl; + // Layouts TQStringList layoutList; - if( config->hasKey("LayoutList") ) { + if (config->hasKey("LayoutList")) + { layoutList = config->readListEntry("LayoutList"); } - else { // old config + else + { // old config TQString mainLayout = config->readEntry("Layout", DEFAULT_LAYOUT_UNIT.toPair()); layoutList = config->readListEntry("Additional"); layoutList.prepend(mainLayout); } - if( layoutList.count() == 0 ) + + if (layoutList.count() == 0) + { layoutList.append("us"); + } + + TQStringList::ConstIterator it; m_layouts.clear(); - for(TQStringList::ConstIterator it = layoutList.begin(); it != layoutList.end() ; ++it) { + for (it = layoutList.begin(); it != layoutList.end(); ++it) + { m_layouts.append( LayoutUnit(*it) ); - kdDebug() << " layout " << LayoutUnit(*it).toPair() << " in list: " << m_layouts.contains( LayoutUnit(*it) ) << endl; + kdDebug() << " layout " << LayoutUnit(*it).toPair() << " in list: " << m_layouts.contains(LayoutUnit(*it)) << endl; } kdDebug() << "Found " << m_layouts.count() << " layouts" << endl; + // Display names TQStringList displayNamesList = config->readListEntry("DisplayNames", ','); - for(TQStringList::ConstIterator it = displayNamesList.begin(); it != displayNamesList.end() ; ++it) { + for (it = displayNamesList.begin(); it != displayNamesList.end() ; ++it) + { TQStringList displayNamePair = TQStringList::split(':', *it ); - if( displayNamePair.count() == 2 ) { - LayoutUnit layoutUnit( displayNamePair[0] ); - if( m_layouts.contains( layoutUnit ) ) { + if (displayNamePair.count() == 2) + { + LayoutUnit layoutUnit(displayNamePair[0]); + if (m_layouts.contains(layoutUnit)) + { m_layouts[m_layouts.findIndex(layoutUnit)].displayName = displayNamePair[1].left(3); } } } + if (loadMode == LOAD_BASIC_OPTIONS) + { + return; + } + + // ALL OTHER OPTIONS (of interest only to KXkb itself) + + // Tray indicator m_showSingle = config->readBoolEntry("ShowSingle", false); + m_showFlag = config->readBoolEntry("ShowFlag", true); m_showLabel = config->readBoolEntry("ShowLabel", true); + m_fitToBox = config->readBoolEntry("FitFlagToBox", true); + m_useThemeColors = config->readBoolEntry("UseThemeColors", false); m_colorBackground = config->readColorEntry("ColorBackground", new TQColor(TQt::gray)); m_bgTransparent = config->readBoolEntry("BgTransparent", false); m_colorLabel = config->readColorEntry("ColorLabel", new TQColor(TQt::white)); + m_labelFont = config->readFontEntry("LabelFont", new TQFont("sans", 10, TQFont::Bold)); m_labelShadow = config->readBoolEntry("LabelShadow", true); m_colorShadow = config->readColorEntry("ColorShadow", new TQColor(TQt::black)); + m_dimFlag = config->readBoolEntry("DimFlag", true); + m_bevel = config->readBoolEntry("IndicatorBevel", false); + + // Switching policy TQString layoutOwner = config->readEntry("SwitchMode", "Global"); - if( layoutOwner == "WinClass" ) { + if (layoutOwner == "WinClass") + { m_switchingPolicy = SWITCH_POLICY_WIN_CLASS; } - else if( layoutOwner == "Window" ) { + else if (layoutOwner == "Window") + { m_switchingPolicy = SWITCH_POLICY_WINDOW; } - else /*if( layoutOwner == "Global" )*/ { + else + { m_switchingPolicy = SWITCH_POLICY_GLOBAL; } - if( m_layouts.count() < 2 && m_switchingPolicy != SWITCH_POLICY_GLOBAL ) { + if (m_layouts.count() < 2 && m_switchingPolicy != SWITCH_POLICY_GLOBAL) + { kdWarning() << "Layout count is less than 2, using Global switching policy" << endl; m_switchingPolicy = SWITCH_POLICY_GLOBAL; } kdDebug() << "Layout owner mode " << layoutOwner << endl; + // Sticky switching m_stickySwitching = config->readBoolEntry("StickySwitching", false); - m_stickySwitchingDepth = config->readEntry("StickySwitchingDepth", "2").toInt(); - if( m_stickySwitchingDepth < 2 ) + m_stickySwitchingDepth = config->readNumEntry("StickySwitchingDepth", 2); + if (m_stickySwitchingDepth < 2) + { m_stickySwitchingDepth = 2; + } - if( m_stickySwitching == true ) { - if( m_layouts.count() < 3 ) { + if (m_stickySwitching) + { + if (m_layouts.count() < 3) + { kdWarning() << "Layout count is less than 3, sticky switching will be off" << endl; m_stickySwitching = false; } - else - if( (int)m_layouts.count() - 1 < m_stickySwitchingDepth ) { + else if (m_layouts.count() - 1 < m_stickySwitchingDepth) + { kdWarning() << "Sticky switching depth is more than layout count -1, adjusting..." << endl; m_stickySwitchingDepth = m_layouts.count() - 1; } } + // Notifications config->setGroup("Notifications"); m_enableNotify = config->readBoolEntry("Enable", false); m_notifyUseKMilo = config->readBoolEntry("UseKMilo", true); delete config; - - return true; } void KxkbConfig::save() @@ -143,55 +181,65 @@ void KxkbConfig::save() TDEConfig *config = new TDEConfig("kxkbrc", false, false); config->setGroup("Layout"); - config->writeEntry("Model", m_model); + config->writeEntry("Use", m_useKxkb); config->writeEntry("ResetOldOptions", m_resetOldOptions); config->writeEntry("Options", m_options ); + config->writeEntry("Model", m_model); + + // Layouts TQStringList layoutList; TQStringList displayNamesList; TQValueList::ConstIterator it; - for(it = m_layouts.begin(); it != m_layouts.end(); ++it) { + for (it = m_layouts.begin(); it != m_layouts.end(); ++it) { const LayoutUnit& layoutUnit = *it; + layoutList.append(layoutUnit.toPair()); - layoutList.append( layoutUnit.toPair() ); - - TQString displayName( layoutUnit.displayName ); - kdDebug() << " displayName " << layoutUnit.toPair() << " : " << displayName << endl; - if( displayName.isEmpty() == false && displayName != layoutUnit.layout ) { + // Display name + TQString displayName(layoutUnit.displayName); + if (!displayName.isEmpty() && displayName != layoutUnit.layout) + { displayName = TQString("%1:%2").arg(layoutUnit.toPair(), displayName); - displayNamesList.append( displayName ); + displayNamesList.append(displayName); } } - config->writeEntry("LayoutList", layoutList); - kdDebug() << "Saving Layouts: " << layoutList << endl; - -// if( displayNamesList.empty() == false ) - config->writeEntry("DisplayNames", displayNamesList); -// else -// config->deleteEntry("DisplayNames"); + config->writeEntry("DisplayNames", displayNamesList); - config->writeEntry("Use", m_useKxkb); + // Tray indicator config->writeEntry("ShowSingle", m_showSingle); config->writeEntry("ShowFlag", m_showFlag); config->writeEntry("ShowLabel", m_showLabel); + config->writeEntry("FitFlagToBox", m_fitToBox); + config->writeEntry("UseThemeColors", m_useThemeColors); config->writeEntry("ColorBackground", m_colorBackground); config->writeEntry("BgTransparent", m_bgTransparent); config->writeEntry("ColorLabel", m_colorLabel); + config->writeEntry("LabelFont", m_labelFont); config->writeEntry("LabelShadow", m_labelShadow); config->writeEntry("ColorShadow", m_colorShadow); + config->writeEntry("DimFlag", m_dimFlag); + config->writeEntry("IndicatorBevel", m_bevel); + + // Switching policy config->writeEntry("SwitchMode", switchModes[m_switchingPolicy]); + // Sticky switching config->writeEntry("StickySwitching", m_stickySwitching); config->writeEntry("StickySwitchingDepth", m_stickySwitchingDepth); + // Notifications + config->setGroup("Notifications"); + config->writeEntry("Enable", m_enableNotify); + config->writeEntry("UseKMilo", m_notifyUseKMilo); + // remove old options config->deleteEntry("Variants"); config->deleteEntry("Includes"); @@ -200,12 +248,7 @@ void KxkbConfig::save() config->deleteEntry("Additional"); config->deleteEntry("Layout"); - config->setGroup("Notifications"); - config->writeEntry("Enable", m_enableNotify); - config->writeEntry("UseKMilo", m_notifyUseKMilo); - config->sync(); - delete config; } @@ -222,6 +265,10 @@ void KxkbConfig::setDefaults() m_useKxkb = false; m_showSingle = false; m_showFlag = true; + m_fitToBox = true; + m_dimFlag = true; + + m_bevel = false; m_switchingPolicy = SWITCH_POLICY_GLOBAL; @@ -229,6 +276,74 @@ void KxkbConfig::setDefaults() m_stickySwitchingDepth = 2; } +bool KxkbConfig::setFromXkbOptions(XkbOptions options) +{ + XkbOptions curOptions = getKXkbOptions(); + + bool modified = false; + + // We need to fix the variants string if it is empty, otherwise the + // comparison below will often wrongly assume that the variants have + // changed + if (options.variants.isEmpty()) + { + options.variants = ""; // ensure the string is empty but not null + for (int i = 0; i < options.layouts.contains(","); ++i) + { + options.variants += ","; + } + } + + // Check if keyboard layout options have changed + if ((options.model != curOptions.model && !options.model.isNull())) + { + modified = true; + m_model = options.model; + } + + if ((options.layouts != curOptions.layouts) || (options.variants != curOptions.variants)) + { + modified = true; + m_layouts.clear(); + + TQStringList layouts = TQStringList::split(",", options.layouts, true); + TQStringList variants = TQStringList::split(",", options.variants, true); + TQStringList::Iterator lit = layouts.begin(); + TQStringList::Iterator vit = variants.begin(); + + if (layouts.empty()) + { + layouts << "us"; + } + + while (lit != layouts.end()) + { + TQString layout = *lit; + TQString variant = vit != variants.end() ? *vit : TQString::null; + m_layouts.append(LayoutUnit(layout, variant)); + + ++lit; + if (vit != variants.end()) + { + ++vit; + } + } + } + + TQStringList serverOpts = TQStringList::split(",", options.options); + TQStringList kxkbOpts = TQStringList::split(",", curOptions.options); + serverOpts.sort(); + kxkbOpts.sort(); + + if (serverOpts != kxkbOpts) + { + modified = true; + m_options = options.options; + } + + return modified; +} + TQStringList KxkbConfig::getLayoutStringList(/*bool compact*/) { TQStringList layoutList; @@ -275,22 +390,25 @@ TQString KxkbConfig::getDefaultDisplayName(const LayoutUnit& layoutUnit, bool si } const XkbOptions KxkbConfig::getKXkbOptions() { - load(LOAD_ALL); - XkbOptions options; TQStringList layouts; TQStringList variants; - for(TQValueList::ConstIterator it = m_layouts.begin(); it != m_layouts.end(); ++it) { + for (TQValueList::ConstIterator it = m_layouts.begin(); it != m_layouts.end(); ++it) { const LayoutUnit& layoutUnit = *it; layouts << layoutUnit.layout; variants << layoutUnit.variant; } options.layouts = layouts.join(","); options.variants = variants.join(","); - options.model = m_model; options.options = m_options; - kdDebug() << "[getKXkbOptions] options: " << m_options << endl; options.resetOld = m_resetOldOptions; + options.model = m_model; + + if (options.model.isEmpty()) + { + options.model = DEFAULT_MODEL; + } + return options; } @@ -329,4 +447,4 @@ const TQString LayoutUnit::parseVariant(const TQString &layvar) if( pos < 2 || len < 2 ) return ""; return varLine.mid(pos+1, len-2); -} \ No newline at end of file +} diff --git a/kxkb/kxkbconfig.h b/kxkb/kxkbconfig.h index 4e424102a..7d02fd3a3 100644 --- a/kxkb/kxkbconfig.h +++ b/kxkb/kxkbconfig.h @@ -45,12 +45,15 @@ extern const char* DEFAULT_MODEL; class KxkbConfig { public: - enum { LOAD_INIT_OPTIONS, LOAD_ACTIVE_OPTIONS, LOAD_ALL }; + enum { LOAD_INIT_OPTIONS, LOAD_BASIC_OPTIONS, LOAD_ALL_OPTIONS }; bool m_useKxkb; bool m_showSingle; bool m_showFlag; bool m_showLabel; + bool m_fitToBox; + bool m_dimFlag; + bool m_bevel; bool m_enableXkbOptions; bool m_resetOldOptions; SwitchingPolicy m_switchingPolicy; @@ -71,7 +74,7 @@ public: TQString m_options; TQValueList m_layouts; - bool load(int loadMode); + void load(int loadMode); void save(); void setDefaults(); @@ -79,6 +82,7 @@ public: static TQString getDefaultDisplayName(const TQString& code_); static TQString getDefaultDisplayName(const LayoutUnit& layoutUnit, bool single=false); + bool setFromXkbOptions(XkbOptions options); const XkbOptions getKXkbOptions(); private: diff --git a/kxkb/kxkbtraywindow.cpp b/kxkb/kxkbtraywindow.cpp index 2d45922b6..7871f443a 100644 --- a/kxkb/kxkbtraywindow.cpp +++ b/kxkb/kxkbtraywindow.cpp @@ -21,105 +21,97 @@ #include "kxkbtraywindow.h" #include "pixmap.h" #include "rules.h" -#include "kxkbconfig.h" - -KxkbLabelController::KxkbLabelController(TQLabel* label_, TDEPopupMenu* contextMenu_) : - label(label_), - contextMenu(contextMenu_), - m_menuStartIndex(contextMenu_->count()), - m_prevLayoutCount(0) +KxkbSystemTray::KxkbSystemTray(KxkbConfig *kxkbConfig) + : KSystemTray(nullptr), + m_prevLayoutCount(0) { -// kdDebug() << "Creating KxkbLabelController with " << label_ << ", " << contextMenu_ << endl; -// kdDebug() << "Creating KxkbLabelController with startMenuIndex " << m_menuStartIndex << endl; + m_icoMgr = new LayoutIconManager(kxkbConfig); } -void KxkbLabelController::setToolTip(const TQString& tip) +KxkbSystemTray::~KxkbSystemTray() { - TQToolTip::remove(label); - TQToolTip::add(label, tip); + delete m_icoMgr; } -void KxkbLabelController::setPixmap(const TQPixmap& pixmap) +void KxkbSystemTray::setToolTip(const TQString& tip) { - TDEIconEffect iconeffect; - label->setPixmap( iconeffect.apply(pixmap, TDEIcon::Panel, TDEIcon::DefaultState) ); + TQToolTip::remove(this); + TQToolTip::add(this, tip); } - -void KxkbLabelController::setCurrentLayout(const LayoutUnit& layoutUnit) +void KxkbSystemTray::setPixmap(const TQPixmap& pix) { - setToolTip(m_descriptionMap[layoutUnit.toPair()]); - setPixmap( LayoutIcon::getInstance().findPixmap(layoutUnit.layout, PIXMAP_STYLE_INDICATOR, layoutUnit.displayName) ); + TDEIconEffect iconeffect; + KSystemTray::setPixmap(iconeffect.apply(pix, TDEIcon::Panel, TDEIcon::DefaultState)); } +void KxkbSystemTray::setCurrentLayout(const LayoutUnit& layoutUnit) +{ + setToolTip(m_descriptionMap[layoutUnit.toPair()]); + setPixmap(m_icoMgr->find(layoutUnit.layout, PIXMAP_STYLE_INDICATOR, layoutUnit.displayName)); +} -void KxkbLabelController::setError(const TQString& layoutInfo) +void KxkbSystemTray::setError(const TQString& layoutInfo) { - TQString msg = i18n("Error changing keyboard layout to '%1'").arg(layoutInfo); - setToolTip(msg); + TQString layout(layoutInfo); + if (layout.isNull()) { + layout = i18n("Unknown"); + } - label->setPixmap(LayoutIcon::getInstance().findPixmap("error", PIXMAP_STYLE_NORMAL)); + TQString msg = i18n("Error changing keyboard layout to '%1'").arg(layoutInfo); + setToolTip(msg); + setPixmap(m_icoMgr->find(ERROR_CODE, PIXMAP_STYLE_NORMAL)); } - -void KxkbLabelController::initLayoutList(const TQValueList& layouts, const XkbRules& rules) +void KxkbSystemTray::initLayoutList(const TQValueList& layouts, const XkbRules& rules) { - TDEPopupMenu* menu = contextMenu; - m_descriptionMap.clear(); - for(int ii=0; iiremoveItem(START_MENU_ID + ii); - kdDebug() << "remove item: " << START_MENU_ID + ii << endl; - } + int i; + for (i = 0; i < m_prevLayoutCount; ++i) { + contextMenu()->removeItem(START_MENU_ID + i); + } TDEIconEffect iconeffect; - int cnt = 0; + i = 0; TQValueList::ConstIterator it; - for (it=layouts.begin(); it != layouts.end(); ++it) + for (it = layouts.begin(); it != layouts.end(); ++it) { - const TQString layoutName = (*it).layout; - const TQString variantName = (*it).variant; + const TQString layoutName = (*it).layout; + const TQString variantName = (*it).variant; + + const TQPixmap& layoutPixmap = m_icoMgr->find((*it).layout, PIXMAP_STYLE_CONTEXTMENU, (*it).displayName); + const TQPixmap pix = iconeffect.apply(layoutPixmap, TDEIcon::Small, TDEIcon::DefaultState); + + TQString fullName = rules.getLayoutName((*it)); + contextMenu()->insertItem(pix, fullName, START_MENU_ID + i, i + 1); - const TQPixmap& layoutPixmap = LayoutIcon::getInstance().findPixmap( - (*it).layout, PIXMAP_STYLE_CONTEXTMENU, (*it).displayName); - const TQPixmap pix = iconeffect.apply(layoutPixmap, TDEIcon::Small, - TDEIcon::DefaultState); + m_descriptionMap.insert((*it).toPair(), fullName); - TQString fullName = rules.getLayoutName((*it)); - contextMenu->insertItem(pix, fullName, START_MENU_ID + cnt, - m_menuStartIndex + cnt); + ++i; + } + + m_prevLayoutCount = i; - m_descriptionMap.insert((*it).toPair(), fullName); + if (contextMenu()->indexOf(CONFIG_MENU_ID) == -1) { + contextMenu()->insertSeparator(); + contextMenu()->insertItem(SmallIcon("configure"), i18n("Configure..."), CONFIG_MENU_ID); - cnt++; + if (contextMenu()->indexOf(HELP_MENU_ID) == -1) { + contextMenu()->insertItem(SmallIcon("help"), i18n("Help"), HELP_MENU_ID); + } } - m_prevLayoutCount = cnt; - - // if show config, if show help - if( menu->indexOf(CONFIG_MENU_ID) == -1 ) { - contextMenu->insertSeparator(); - contextMenu->insertItem(SmallIcon("configure"), i18n("Configure..."), CONFIG_MENU_ID); - if( menu->indexOf(HELP_MENU_ID) == -1 ) - contextMenu->insertItem(SmallIcon("help"), i18n("Help"), HELP_MENU_ID); - } - -/* if( index != -1 ) { //not first start - menu->insertSeparator(); - TDEAction* quitAction = KStdAction::quit(this, TQ_SIGNAL(quitSelected()), actionCollection()); - if (quitAction) - quitAction->plug(menu); - }*/ + connect(contextMenu(), TQ_SIGNAL(activated(int)), this, TQ_SIGNAL(menuActivated(int))); } -// void KxkbLabelController::mouseReleaseEvent(TQMouseEvent *ev) -// { -// if (ev->button() == TQMouseEvent::LeftButton) -// emit toggled(); -// KSystemTray::mouseReleaseEvent(ev); -// } +void KxkbSystemTray::mouseReleaseEvent(TQMouseEvent *ev) { + if (ev->button() == TQt::LeftButton) { + emit toggled(); + } + KSystemTray::mouseReleaseEvent(ev); +} #include "kxkbtraywindow.moc" diff --git a/kxkb/kxkbtraywindow.h b/kxkb/kxkbtraywindow.h index 46d66c44b..3e1ae2c05 100644 --- a/kxkb/kxkbtraywindow.h +++ b/kxkb/kxkbtraywindow.h @@ -1,7 +1,7 @@ // // C++ Interface: kxkbtraywindow // -// Description: +// Description: // // // Author: Andriy Rysin , (C) 2006 @@ -17,77 +17,40 @@ #include #include -#include "kxkbconfig.h" +#include "layoutunit.h" - -class TQLabel; -class TDEPopupMenu; class XkbRules; +class KxkbConfig; +class LayoutIconManager; -/* This class is responsible for displaying flag/label for the layout, - catching keyboard/mouse events and displaying menu when selected -*/ - -class KxkbLabelController: public TQObject +class KxkbSystemTray : public KSystemTray { -// TQ_OBJECT - -public: - enum { START_MENU_ID = 100, CONFIG_MENU_ID = 130, HELP_MENU_ID = 131 }; - - KxkbLabelController(TQLabel *label, TDEPopupMenu* contextMenu); + TQ_OBJECT - void initLayoutList(const TQValueList& layouts, const XkbRules& rule); - void setCurrentLayout(const LayoutUnit& layout); -// void setCurrentLayout(const TQString& layout, const TQString &variant); - void setError(const TQString& layoutInfo=""); - void setShowFlag(bool showFlag) { m_showFlag = showFlag; } - void show() { label->show(); } + public: + KxkbSystemTray(KxkbConfig *kxkbConfig); + ~KxkbSystemTray(); + void initLayoutList(const TQValueList& layouts, const XkbRules& rule); + void setCurrentLayout(const LayoutUnit& layout); + void setError(const TQString& layoutInfo = TQString::null); - WId winId() { return label->winId(); } - -// signals: -// -// void menuActivated(int); -// void toggled(); + enum { START_MENU_ID = 100, CONFIG_MENU_ID = 130, HELP_MENU_ID = 131 }; -// protected: -// -// void mouseReleaseEvent(TQMouseEvent *); - -private: - TQLabel* label; - TDEPopupMenu* contextMenu; - - const int m_menuStartIndex; - bool m_showFlag; - int m_prevLayoutCount; - TQMap m_descriptionMap; - - void setToolTip(const TQString& tip); - void setPixmap(const TQPixmap& pixmap); -}; + protected: + void mouseReleaseEvent(TQMouseEvent *ev); + private slots: + void setToolTip(const TQString& tip); + void setPixmap(const TQPixmap& pix); -class KxkbSystemTray : public KSystemTray -{ - TQ_OBJECT - - public: - KxkbSystemTray(): - KSystemTray(NULL) - {} - - void mouseReleaseEvent(TQMouseEvent *ev) - { - if (ev->button() == TQt::LeftButton) - emit toggled(); - KSystemTray::mouseReleaseEvent(ev); - } + signals: + void menuActivated(int); + void toggled(); - signals: - void menuActivated(int); - void toggled(); + private: + LayoutIconManager *m_icoMgr; + int m_prevLayoutCount; + TQMap m_descriptionMap; }; diff --git a/kxkb/pixmap.cpp b/kxkb/pixmap.cpp index e7f720ca1..01866e71e 100644 --- a/kxkb/pixmap.cpp +++ b/kxkb/pixmap.cpp @@ -1,9 +1,11 @@ +#include #include #include #include #include #include #include +#include #include #include @@ -13,56 +15,42 @@ #include "pixmap.h" #include "x11helper.h" +const TQString LayoutIconManager::flagTemplate("l10n/%1/flag.png"); -static const int FLAG_MAX_DIM = 24; - -const TQString LayoutIcon::flagTemplate("l10n/%1/flag.png"); -const TQString& LayoutIcon::ERROR_CODE("error"); -LayoutIcon* LayoutIcon::instance; - - -LayoutIcon& LayoutIcon::getInstance() { - if( instance == NULL ) { - instance = new LayoutIcon(); - } - return *instance; -} - -LayoutIcon::LayoutIcon(): - m_pixmapCache(80) +LayoutIconManager::LayoutIconManager(KxkbConfig *kxkbConfig) + : m_pixmapCache(80), + m_kxkbConfig(kxkbConfig) { } -const TQPixmap& -LayoutIcon::findPixmap(const TQString& code_, int pixmapStyle, const TQString& displayName_) +const TQPixmap& LayoutIconManager::find(const TQString& code_, int pixmapStyle, const TQString& displayName_) { - m_kxkbConfig.load(KxkbConfig::LOAD_ALL); // (re)load settings - - if (m_kxkbConfig.m_useThemeColors) { // use colors from color scheme + if (m_kxkbConfig->m_useThemeColors) { // use colors from color scheme m_bgColor = TDEGlobalSettings::highlightColor(); m_fgColor = TDEGlobalSettings::highlightedTextColor(); } else { - m_bgColor = m_kxkbConfig.m_colorBackground; - m_fgColor = m_kxkbConfig.m_colorLabel; + m_bgColor = m_kxkbConfig->m_colorBackground; + m_fgColor = m_kxkbConfig->m_colorLabel; } - m_labelFont = m_kxkbConfig.m_labelFont; - m_labelShadow = m_kxkbConfig.m_labelShadow; - m_shColor = m_kxkbConfig.m_colorShadow; - m_bgTransparent = m_kxkbConfig.m_bgTransparent; + m_labelFont = m_kxkbConfig->m_labelFont; + m_labelShadow = m_kxkbConfig->m_labelShadow; + m_shColor = m_kxkbConfig->m_colorShadow; + m_bgTransparent = m_kxkbConfig->m_bgTransparent; + m_fitToBox = m_kxkbConfig->m_fitToBox; + m_dimFlag = m_kxkbConfig->m_dimFlag; + m_bevel = m_kxkbConfig->m_bevel && !m_bgTransparent && pixmapStyle == PIXMAP_STYLE_INDICATOR; // Decide on how to style the pixmap switch(pixmapStyle) { case PIXMAP_STYLE_NORMAL: - m_fitToBox = true; m_showFlag = true; m_showLabel = false; break; case PIXMAP_STYLE_INDICATOR: - m_fitToBox = true; - m_showFlag = m_kxkbConfig.m_showFlag; - m_showLabel = m_kxkbConfig.m_showLabel; + m_showFlag = m_kxkbConfig->m_showFlag; + m_showLabel = m_kxkbConfig->m_showLabel; break; case PIXMAP_STYLE_CONTEXTMENU: @@ -73,7 +61,7 @@ LayoutIcon::findPixmap(const TQString& code_, int pixmapStyle, const TQString& d } // Label only mode is always 'fit to box' - if( m_showLabel && !m_showFlag ) + if (m_showLabel && !m_showFlag) m_fitToBox = true; TQPixmap* pm = NULL; @@ -89,57 +77,92 @@ LayoutIcon::findPixmap(const TQString& code_, int pixmapStyle, const TQString& d TQString displayName(displayName_); - if( displayName.isEmpty() ) { + if (displayName.isEmpty()) { displayName = KxkbConfig::getDefaultDisplayName(code_); } - if( displayName.length() > 3 ) + if (displayName.length() > 3) displayName = displayName.left(3); const TQString pixmapKey( - TQString( m_showFlag ? "f" : "" ) + TQString( m_showLabel ? "l" : "" ) + TQString( m_labelShadow ? "s" : "" ) + "." + + TQString(m_showFlag ? "f" : "") + TQString(m_showLabel ? "l" : "") + TQString(m_labelShadow ? "s" : "") + "." + + TQString(m_fitToBox ? "F" : "") + TQString(m_dimFlag ? "D" : "") + TQString(m_bevel ? "B" : "") + "." + m_labelFont.key() + "." + ( m_bgTransparent ? "x" : m_bgColor.name() ) + "." + m_fgColor.name() + "." + m_shColor.name() + '.' + code_ + "." + displayName ); // Only use cache for indicator - if( pixmapStyle == PIXMAP_STYLE_INDICATOR ) { + if (pixmapStyle == PIXMAP_STYLE_INDICATOR) { pm = m_pixmapCache[pixmapKey]; - if( pm ) + if (pm) return *pm; } - // Need to create new pixmap - pm = new TQPixmap(); + pm = new TQPixmap(FLAG_MAX_DIM, FLAG_MAX_DIM); - if( m_fitToBox ) // Resize to box size - pm->resize(FLAG_MAX_DIM, FLAG_MAX_DIM); + TQRect r = pm->rect(); + TQPainter p_(pm); - if( m_showFlag ) { - TQString countryCode = getCountryFromLayoutName( code_ ); + if (m_showFlag) { + TQString countryCode = getCountryFromLayoutName(code_); TQString flag = locate("locale", flagTemplate.arg(countryCode)); - if( flag.isEmpty() ) { + if (flag.isEmpty()) { pm->fill(m_bgColor); m_showLabel = true; } else { - if( m_fitToBox ) { // Resize flag - TQPainter p_(pm); - p_.drawPixmap(TQRect(0, 0, FLAG_MAX_DIM, FLAG_MAX_DIM), flag); - } else { // Show the flag as is - pm->load(flag); + TQPixmap fp(flag); + + if (m_dimFlag && m_showLabel) + { + TQImage image = fp.convertToImage(); + for (int y = 0; y < image.height(); y++) + { + for(int x = 0; x < image.width(); x++) + { + TQRgb rgb = image.pixel(x,y); + TQRgb dimRgb(tqRgb(tqRed(rgb) * 3/4, tqGreen(rgb) * 3/4, tqBlue(rgb) * 3/4)); + image.setPixel(x, y, dimRgb); + } + } + fp.convertFromImage(image); + } + + if (!m_fitToBox) + { + r = TQRect((FLAG_MAX_DIM - fp.width()) / 2, (FLAG_MAX_DIM - fp.height()) / 2, fp.width(), fp.height()); + } + + TQRect fr(r); // flag rect might be smaller to accomodate the bevel + if (m_bevel) + { + fr.setX(fr.x() + 1); + fr.setY(fr.y() + 1); + fr.setWidth(fr.width() - 1); + fr.setHeight(fr.height() - 1); } - if( m_showLabel ) // only dim for label - dimPixmap( *pm ); + p_.drawPixmap(fr, fp); + + // If we don't stretch the flag, we need to apply a mask to it + if (!m_fitToBox) + { + TQPixmap fpmask(FLAG_MAX_DIM, FLAG_MAX_DIM); + TQPainter fpmaskp(&fpmask); + fpmask.fill(TQt::white); + fpmaskp.fillRect(r, TQt::black); + TQBitmap fpmask_; + fpmask_ = fpmask; + pm->setMask((TQBitmap)fpmask_); + } } } else { pm->fill(m_bgColor); } - if( m_showLabel ) { + if (m_showLabel) { TQPainter p(pm); p.setFont(m_labelFont); - if( m_labelShadow ) { + if (m_labelShadow) { p.setPen(m_shColor); p.drawText(1, 1, pm->width(), pm->height(), TQt::AlignCenter, displayName); } @@ -168,8 +191,14 @@ LayoutIcon::findPixmap(const TQString& code_, int pixmapStyle, const TQString& d } } + if (m_bevel) + { + TQPainter p_(pm); + qDrawShadePanel(&p_, r.x(), r.y(), r.width(), r.height(), tqApp->palette().active(), false, 1, nullptr); + } + - if( pixmapStyle == PIXMAP_STYLE_INDICATOR ) + if (pixmapStyle == PIXMAP_STYLE_INDICATOR) m_pixmapCache.insert(pixmapKey, pm); return *pm; @@ -178,7 +207,7 @@ LayoutIcon::findPixmap(const TQString& code_, int pixmapStyle, const TQString& d /** @brief Try to get country code from layout name in xkb before xorg 6.9.0 */ -TQString LayoutIcon::getCountryFromLayoutName(const TQString& layoutName) +TQString LayoutIconManager::getCountryFromLayoutName(const TQString& layoutName) { TQString flag; @@ -285,24 +314,8 @@ TQString LayoutIcon::getCountryFromLayoutName(const TQString& layoutName) return flag; } - -void LayoutIcon::dimPixmap(TQPixmap& pm) -{ - TQImage image = pm.convertToImage(); - for (int y=0; yfill(TQt::white); diff --git a/kxkb/pixmap.h b/kxkb/pixmap.h index a17f48d89..08dee8a87 100644 --- a/kxkb/pixmap.h +++ b/kxkb/pixmap.h @@ -8,41 +8,34 @@ #include "kxkbconfig.h" -enum PixmapStyle { - PIXMAP_STYLE_NORMAL = 0, - PIXMAP_STYLE_INDICATOR = 1, - PIXMAP_STYLE_CONTEXTMENU = 2 -}; - -class LayoutIcon { +#define ERROR_CODE "error" +#define ERROR_LABEL "!" -private: - static LayoutIcon* instance; - static const TQString flagTemplate; +#define FLAG_MAX_DIM 24 - KxkbConfig m_kxkbConfig; - bool m_showFlag; - bool m_showLabel; - TQColor m_bgColor; - bool m_bgTransparent; - TQColor m_fgColor; - TQFont m_labelFont; - bool m_labelShadow; - TQColor m_shColor; - bool m_fitToBox; +enum PixmapStyle { + PIXMAP_STYLE_NORMAL = 0, + PIXMAP_STYLE_INDICATOR = 1, + PIXMAP_STYLE_CONTEXTMENU = 2 +}; - TQDict m_pixmapCache; +class LayoutIconManager { + public: + LayoutIconManager(KxkbConfig *kxkbConfig); + const TQPixmap& find(const TQString& code, int pixmapStyle, const TQString& displayName = TQString::null); - LayoutIcon(); - TQPixmap* createErrorPixmap(); - void dimPixmap(TQPixmap& pixmap); - TQString getCountryFromLayoutName(const TQString& layoutName); + private: + TQPixmap* createErrorPixmap(); + TQString getCountryFromLayoutName(const TQString& layoutName); -public: - static const TQString& ERROR_CODE; + private: + KxkbConfig *m_kxkbConfig; + static const TQString flagTemplate; + bool m_showFlag, m_showLabel, m_bgTransparent, m_labelShadow, m_fitToBox, m_dimFlag, m_bevel; + TQColor m_bgColor, m_fgColor, m_shColor; + TQFont m_labelFont; - static LayoutIcon& getInstance(); - const TQPixmap& findPixmap(const TQString& code, int pixmapStyle, const TQString& displayName=""); + TQDict m_pixmapCache; }; #endif