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>
pull/550/head
Mavridis Philippe 11 months ago
parent 1686be58c6
commit aed24cdf3f

@ -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}
)

@ -6,3 +6,8 @@ Comment=TDE Keyboard Tool
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

@ -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<EFBFBD>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)
{
if ( d == NULL )
d = tqt_xdisplay();
m_dpy = d;
static XKBExtension *xkbExtension = nullptr;
// TQStringList dirs = TDEGlobal::dirs()->findDirs ( "tmp", "" );
// m_tempDir = dirs.count() == 0 ? "/tmp/" : dirs[0];
m_tempDir = locateLocal("tmp", "");
XKBExtension *XKBExtension::the()
{
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;
@ -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"

@ -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<EFBFBD>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

@ -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;
}
}

@ -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;

@ -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>

@ -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;
kdDebug() << "applying xkb options and layouts" << endl;
kxkbConfig.load(KxkbConfig::LOAD_ALL_OPTIONS);
applyXkbOptions();
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
}
// Active window watcher
m_prevWinId = X11Helper::UNKNOWN_WINDOW_ID;
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;
}
if (kxkbConfig.m_switchingPolicy == SWITCH_POLICY_GLOBAL)
{
delete kWinModule;
kWinModule = nullptr;
}
m_layoutOwnerMap->reset();
m_layoutOwnerMap->setCurrentWindow( m_prevWinId );
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;
}
if( m_rules == NULL )
m_rules = new XkbRules(false);
// Init layout owner map
m_layoutOwnerMap->reset();
m_layoutOwnerMap->setCurrentWindow( m_prevWinId );
for(int ii=0; ii<(int)kxkbConfig.m_layouts.count(); ii++) {
LayoutUnit& layoutUnit = kxkbConfig.m_layouts[ii];
}
// Init rules
if (!m_rules)
{
m_rules = new XkbRules(false);
}
m_currentLayout = kxkbConfig.m_layouts[0];
kdDebug() << "default layout is " << m_currentLayout.toPair() << endl;
// Init layouts
for (int i = 0; i < kxkbConfig.m_layouts.count(); i++)
{
LayoutUnit& layoutUnit = kxkbConfig.m_layouts[i];
}
if( kxkbConfig.m_layouts.count() == 1 && !kxkbConfig.m_showSingle) {
tdeApp->quit();
return false;
}
m_currentLayout = kxkbConfig.m_layouts[0];
setLayout(m_currentLayout);
initTray();
kdDebug() << "default layout is " << m_currentLayout.toPair() << endl;
TDEGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
keys->readSettings();
keys->updateConnections();
if (kxkbConfig.m_layouts.count() == 1 && !kxkbConfig.m_showSingle)
{
quit();
return;
}
return true;
}
TDEGlobal::config()->reparseConfiguration(); // kcontrol modified kdeglobals
void KXKBApp::initTray()
{
if( !m_tray )
{
KSystemTray* sysTray = new KxkbSystemTray();
TDEPopupMenu* popupMenu = sysTray->contextMenu();
// popupMenu->insertTitle( tdeApp->miniIcon(), tdeApp->caption() );
// 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 = 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->initLayoutList(kxkbConfig.m_layouts, *m_rules);
m_tray->setCurrentLayout(m_currentLayout);
m_tray->show();
m_tray->setShowFlag(kxkbConfig.m_showFlag);
m_tray->initLayoutList(kxkbConfig.m_layouts, *m_rules);
m_tray->setCurrentLayout(m_currentLayout);
m_tray->show();
// Init keybindings
keys->readSettings();
keys->updateConnections();
}
// This function activates the keyboard layout specified by the
// configuration members (m_currentLayout)
void KXKBApp::layoutApply()
void KXKBApp::applyXkbOptions()
{
setLayout(m_currentLayout);
XkbOptions options = kxkbConfig.getKXkbOptions();
if (!XKBExtension::the()->setXkbOptions(options)) {
kdWarning() << "Setting XKB options failed!" << endl;
}
}
void KXKBApp::hardwareChanged(TDEGenericDevice *dev)
{
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;
}
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);
void KXKBApp::maybeShowLayoutNotification() {
if (!kxkbConfig.m_enableNotify) return;
if (m_tray) {
m_tray->setCurrentLayout(m_currentLayout);
}
TQString layoutName(m_rules->getLayoutName(m_currentLayout));
bool useKMilo = kxkbConfig.m_notifyUseKMilo;
bool notificationSent = false;
if (kxkbConfig.m_enableNotify) {
showLayoutNotification();
}
}
// 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::slotSyncXkbOptions()
{
// Make sure the X11 server has had enough time to apply the change
TQTimer::singleShot(100, this, TQ_SLOT(syncXkbOptions()));
}
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
@ -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);
}

@ -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;

@ -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;
config->writeEntry("DisplayNames", displayNamesList);
// if( displayNamesList.empty() == false )
config->writeEntry("DisplayNames", displayNamesList);
// else
// config->deleteEntry("DisplayNames");
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;
}

@ -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:

@ -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"

@ -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);
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(); }
WId winId() { return label->winId(); }
// signals:
//
// void menuActivated(int);
// void toggled();
// protected:
//
// void mouseReleaseEvent(TQMouseEvent *);
private:
TQLabel* label;
TDEPopupMenu* contextMenu;
TQ_OBJECT
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);
};
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);
enum { START_MENU_ID = 100, CONFIG_MENU_ID = 130, HELP_MENU_ID = 131 };
class KxkbSystemTray : public KSystemTray
{
TQ_OBJECT
protected:
void mouseReleaseEvent(TQMouseEvent *ev);
public:
KxkbSystemTray():
KSystemTray(NULL)
{}
private slots:
void setToolTip(const TQString& tip);
void setPixmap(const TQPixmap& pix);
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;
};

@ -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);

@ -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

Loading…
Cancel
Save