summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMavridis Philippe <mavridisf@gmail.com>2024-10-28 14:40:20 +0200
committerMavridis Philippe <mavridisf@gmail.com>2025-04-03 11:47:21 +0000
commitaed24cdf3fd4615b0ac42fad074f20c0427cc3ac (patch)
tree21f348286454071ffbf35ae475b9b041695a19b5
parent1686be58c6c34303f33803db2bc8688e634bf6cd (diff)
downloadtdebase-aed24cdf3fd4615b0ac42fad074f20c0427cc3ac.tar.gz
tdebase-aed24cdf3fd4615b0ac42fad074f20c0427cc3ac.zip
Kxkb: layout switching and UI bugfixes and minor refactoring
* Layout switching - Improved layout change logic (indicator is now always updated when the actual switch occurs). This fixes layout switching triggered by the X11 shortcut not being synchronized with layout switching from the tray icon click and the TDE shortcut. - Kxkb will ignore XkbStateNotify events not related to XkbGroupState which caused strange behaviour with the system tray context menu. - Reapply Xkb settings when a keyboard device changes state - Do not run setxkbmap without arguments - Catch and process changes to Xkb layouts and options - Always check for Xkb opcode in X11 events, this fixes invalid group issue (Michele Calgaro) * Tray indicator - Do not reload all Kxkb settings every time we are requested to get a pixmap! - Tray indicator pixmap manager improvements - Fix Quit tray icon menu item * Configuration - Optimize settings reloading - Do not reload settings every time getKxkbOptions() is called; if settings actually need to be re-read, it must be done maunally before calling this function - Use pointer to global KxkbConfig instance instead of keeping own copy - Fixed optimized loading of initial settings using KxkbConfig::LOAD_INIT_OPTIONS (I had sort of broken it in the past) - Removed unused KxkbConfig::LOAD_ACTIVE_OPTIONS - `newInstance()` now delegates calling setLayout() to readSettings() - Merged `initTray()` into `readSettings()` - no reason to exist as separate function * Refactoring - Merged KxkbLabelController into KxkbSystemTray - Rename LayoutIcon to LayoutIconManager for clarity - Minor code cleanup in LayoutIconManager - Remove use of singleton pattern for LayoutIconManager - Make XKBExtension a singleton. - Add mutex to XKBExtension to prevent it from processing configuration changes likely caused by KXkb - `XKBExtension::getServerOptions()` now also returns layout and variant information in a XkbOptions struct - New `KxkbConfig::setFromXkbOptions()` member can update current configuration from a XkbOptions struct - No need to use `tdeApp` pointer in KXKBApp (KUniqueApplication) class - Consistent code style and more appropriate function names and return types - Commented option sections for clarity - Removed superfluous debug messages - Add proper copyright header to extension.* * Settings GUI - Make "Transparent background" checkbox available for theme colors in the GUI - Add customization options "Stretch flag", "Dim flag", "Show indicator bevel" - Disable KMilo checkbox when layout notifications disabled - Fix reading settings for TDE layout hotkeys This resolves #547. Signed-off-by: Mavridis Philippe <mavridisf@gmail.com> Signed-off-by: Michele Calgaro <michele.calgaro@yahoo.it>
-rw-r--r--kxkb/CMakeLists.txt2
-rw-r--r--kxkb/eventsrc5
-rw-r--r--kxkb/extension.cpp230
-rw-r--r--kxkb/extension.h61
-rw-r--r--kxkb/kcmlayout.cpp59
-rw-r--r--kxkb/kcmlayout.h8
-rw-r--r--kxkb/kcmlayoutwidget.ui118
-rw-r--r--kxkb/kxkb.cpp439
-rw-r--r--kxkb/kxkb.h17
-rw-r--r--kxkb/kxkbconfig.cpp236
-rw-r--r--kxkb/kxkbconfig.h8
-rw-r--r--kxkb/kxkbtraywindow.cpp124
-rw-r--r--kxkb/kxkbtraywindow.h87
-rw-r--r--kxkb/pixmap.cpp157
-rw-r--r--kxkb/pixmap.h51
15 files changed, 1002 insertions, 600 deletions
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 <srhaque@iee.org>
+
+ 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 <lz@europe.com>
+
+ 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 <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -5,10 +34,13 @@
#include <tqmap.h>
#include <tqfile.h>
#include <tqdir.h>
+#include <tqtimer.h>
#include <kdebug.h>
+#include <tdeapplication.h>
#include <tdestandarddirs.h>
#include <tdeprocess.h>
+#include <dcopclient.h>
#include <X11/Xatom.h>
#include <X11/Xos.h>
@@ -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 <srhaque@iee.org>
+
+ 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 <lz@europe.com>
+
+ 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 <X11/Xlib.h>
+
#include <tqobject.h>
#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<TQString, FILE*> 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 <tqbuttongroup.h>
#include <tqspinbox.h>
#include <tqvbox.h>
+#include <tqtimer.h>
#include <tdefontrequester.h>
#include <kcolorbutton.h>
@@ -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<LayoutUnit> 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 @@
<rect>
<x>0</x>
<y>0</y>
- <width>709</width>
- <height>563</height>
+ <width>700</width>
+ <height>600</height>
</rect>
</property>
<property name="sizePolicy">
@@ -22,8 +22,8 @@
</property>
<property name="minimumSize">
<size>
- <width>600</width>
- <height>510</height>
+ <width>700</width>
+ <height>600</height>
</size>
</property>
<grid>
@@ -904,36 +904,19 @@
</size>
</property>
</spacer>
- <spacer row="4" column="0">
- <property name="name">
- <cstring>spacer22</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Fixed</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="TQCheckBox" row="4" column="1" rowspan="1" colspan="3">
- <property name="name">
- <cstring>chkBgTransparent</cstring>
- </property>
- <property name="text">
- <string>Transparent background</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string>Check this to remove the indicator's background. Only applicable in "Label only" mode.</string>
- </property>
- </widget>
</grid>
</widget>
+ <widget class="TQCheckBox" row="4" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>chkBgTransparent</cstring>
+ </property>
+ <property name="text">
+ <string>Transparent background</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Check this to remove the indicator's background. Only applicable in "Label only" mode.</string>
+ </property>
+ </widget>
<widget class="KSeparator" row="5" column="0" rowspan="1" colspan="3">
<property name="name">
<cstring>separator1</cstring>
@@ -992,7 +975,8 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
- </widget> <spacer row="7" column="2">
+ </widget>
+ <spacer row="7" column="2">
<property name="name">
<cstring>spacer23</cstring>
</property>
@@ -1011,6 +995,35 @@
</spacer>
</grid>
</widget>
+ <widget class="TQButtonGroup" row="2" column="0" column="0" colspan="2">
+ <property name="name">
+ <cstring>grpFlag</cstring>
+ </property>
+ <property name="title">
+ <string>Flag Style</string>
+ </property>
+ <vbox>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkFitToBox</cstring>
+ </property>
+ <property name="text">
+ <string>Stretc&amp;h flag</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If this option is enabled, the flag will be stretched to fit the tray indicator size.</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkDimFlag</cstring>
+ </property>
+ <property name="text">
+ <string>Dim flag to make the label more visible</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
<widget class="TQButtonGroup" row="0" column="1">
<property name="name">
<cstring>grpMisc</cstring>
@@ -1027,6 +1040,17 @@
<string>Show indicator for single layout</string>
</property>
</widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>chkBevel</cstring>
+ </property>
+ <property name="text">
+ <string>Show indicator bevel</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If this option is enabled, the layout indicator will be drawn with a thin 3D bevel around it.</string>
+ </property>
+ </widget>
</vbox>
</widget>
</grid>
@@ -1209,8 +1233,8 @@
<signal>toggled(bool)</signal>
<receiver>bgColor</receiver>
<slot>setEnabled(bool)</slot>
- </connection>
- <connection>
+ </connection>
+ <connection>
<sender>radLabelOnly</sender>
<signal>toggled(bool)</signal>
<receiver>labelBgColor</receiver>
@@ -1234,6 +1258,30 @@
<receiver>chkNotifyUseKMilo</receiver>
<slot>setEnabled(bool)</slot>
</connection>
+ <connection>
+ <sender>radFlagOnly</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>grpFlag</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radFlagLabel</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>grpFlag</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radLabelOnly</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>grpFlag</receiver>
+ <slot>setDisabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radFlagLabel</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>chkDimFlag</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
</connections>
<includes>
<include location="local" impldecl="in implementation">kiconloader.h</include>
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 <unistd.h>
-#include <stdlib.h>
#include <assert.h>
#include <tqregexp.h>
#include <tqfile.h>
#include <tqstringlist.h>
#include <tqimage.h>
+#include <tqtimer.h>
#include <tdeaboutdata.h>
#include <tdecmdlineargs.h>
+#include <tdehardwaredevices.h>
#include <tdeglobal.h>
#include <tdeglobalaccel.h>
#include <tdelocale.h>
@@ -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 <tqptrqueue.h>
#include <tdeuniqueapplication.h>
+#include <tdegenericdevice.h>
#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<LayoutUnit>::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<LayoutUnit>::ConstIterator it = m_layouts.begin(); it != m_layouts.end(); ++it) {
+ for (TQValueList<LayoutUnit>::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<LayoutUnit> 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<LayoutUnit>& layouts, const XkbRules& rules)
+void KxkbSystemTray::initLayoutList(const TQValueList<LayoutUnit>& layouts, const XkbRules& rules)
{
- TDEPopupMenu* menu = contextMenu;
-
m_descriptionMap.clear();
- for(int ii=0; ii<m_prevLayoutCount; ++ii) {
- menu->removeItem(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<LayoutUnit>::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 <rysin@kde.org>, (C) 2006
@@ -17,77 +17,40 @@
#include <tqstring.h>
#include <tqvaluelist.h>
-#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<LayoutUnit>& 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<LayoutUnit>& 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<TQString, TQString> 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<TQString, TQString> 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 <tqapplication.h>
#include <tqimage.h>
#include <tqbitmap.h>
#include <tqfont.h>
#include <tqpainter.h>
#include <tqregexp.h>
#include <tqdict.h>
+#include <tqdrawutil.h>
#include <tdestandarddirs.h>
#include <tdeglobalsettings.h>
@@ -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; 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);
- }
- pm.convertFromImage(image);
-}
-
-static const char* ERROR_LABEL = "err";
-
//private
-TQPixmap* LayoutIcon::createErrorPixmap()
+TQPixmap* LayoutIconManager::createErrorPixmap()
{
TQPixmap* pm = new TQPixmap(21, 14);
pm->fill(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<TQPixmap> 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<TQPixmap> m_pixmapCache;
};
#endif