You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kkbswitch/kkbswitch/kbswitchapp.cpp

392 lines
12 KiB

/***************************************************************************
kbswitchapp.cpp - description
-------------------
begin : Sun Jul 1 2001
copyright : (C) 2001 by Leonid Zeitlin
email : lz@europe.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "config.h"
#include "kbswitchapp.h"
#include "kbconfigdlg.h"
#include "singlewindowwatcher.h"
#include "windowclasswatcher.h"
#include <kdebug.h>
#include <tdelocale.h>
#include <twinmodule.h>
KBSwitchApp::KBSwitchApp()
{
#ifndef HAVE_LIBXKLAVIER
//m_twin_module = NULL;
m_watcher = NULL;
#endif
if (!m_xkb.xkbAvailable()) return; // oops! No XKB in the server
m_kbconf.load(config());
m_cur_groupno = m_next_groupno = -1;
#ifdef HAVE_LIBXKLAVIER
XklSetGroupPerApp(m_kbconf.group_scope() != KBConfig::SCOPE_GLOBAL);
if (m_kbconf.toggle_mode())
XklSetSecondaryGroupsMask(12); /* binary 1100 */
#else
//resetWindowMap();
//enableKWinModule();
enableWatcher();
#endif
m_intf = new KBSwitchIntf(this, &m_kbconf);
TQObject::connect(m_intf, TQ_SIGNAL(nextGroupSelected()), this, TQ_SLOT(slotSelectNextGroup()));
TQObject::connect(m_intf, TQ_SIGNAL(groupSelected(int)), this, TQ_SLOT(slotGroupSelected(int)));
TQObject::connect(&m_xkb, TQ_SIGNAL(layoutChanged()), this, TQ_SLOT(reconfigure()));
TQObject::connect(&m_xkb, TQ_SIGNAL(groupChanged(int)), this, TQ_SLOT(slotXkbGroupChanged(int)));
m_force_group_setting = false;
int start_group = m_kbconf.default_groupno();
m_trayicon = new KBSwitchTrayIcon(&m_kbconf);
TQObject::connect(m_trayicon, TQ_SIGNAL(groupSelected(int)), this,
TQ_SLOT(slotGroupSelected(int)));
TQObject::connect(m_trayicon, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotSelectNextGroup()));
TQObject::connect(m_trayicon, TQ_SIGNAL(preferencesSelected()), this,
TQ_SLOT(slotPreferences()));
if (start_group != m_xkb.getGroupNo()) {
setStartGroup(start_group);
}
else {
adaptToGroup(start_group);
}
setMainWidget(m_trayicon);
m_trayicon->show();
#ifdef HAVE_LIBXKLAVIER
XklStartListen();
#endif
}
KBSwitchApp::~KBSwitchApp(){
#ifndef HAVE_LIBXKLAVIER
//disableKWinModule();
disableWatcher();
#endif
}
/** No descriptions */
bool KBSwitchApp::x11EventFilter(XEvent *e){
// let m_xkb process the event and emit signals if necessary
m_xkb.processEvent(e);
return TDEApplication::x11EventFilter(e);
}
/** Update the tray icon to show the flag corresponding to the current keyboard group */
void KBSwitchApp::updateIcon(int groupno){
if (groupno >= 0 && groupno < m_kbconf.groupCount()) { // check just in case
m_trayicon->updateTrayIcon(groupno);
if (m_kbconf.toggle_mode()) m_trayicon->setToggleGroups(m_cur_groupno, m_next_groupno);
}
}
/** No descriptions */
void KBSwitchApp::slotGroupSelected(int groupno)
{
#ifdef HAVE_LIBXKLAVIER
XklAllowOneSwitchToSecondaryGroup();
m_xkb.setGroupNo(groupno);
#else
if (m_cur_groupno != groupno) {
setGroups(groupno, m_cur_groupno);
}
#endif
}
/** No descriptions */
void KBSwitchApp::internalToggleGroups()
{
int tmp = m_next_groupno;
m_next_groupno = m_cur_groupno;
m_cur_groupno = tmp;
}
/** No descriptions */
void KBSwitchApp::forceSetGroup(int groupno)
{
m_force_group_setting = true;
#ifndef HAVE_LIBXKLAVIER
//if (m_active_window != m_window_map.end())
// m_active_window.data().groupno = groupno;
#endif
m_xkb.setGroupNo(groupno);
}
/** Select the next keyboard layout (wraps around) */
void KBSwitchApp::slotSelectNextGroup()
{
#ifdef HAVE_LIBXKLAVIER
m_xkb.setGroupNo(XklGetNextGroup());
#else
//forceSetGroup(m_next_groupno);
m_xkb.setGroupNo(m_next_groupno);
#endif
}
/** Select the previous keyboard layout (wraps around) */
void KBSwitchApp::slotSelectPrevGroup()
{
#ifdef HAVE_LIBXKLAVIER
m_xkb.setGroupNo(XklGetPrevGroup());
#else
m_xkb.setGroupNo(m_kbconf.getPrevGroup(m_cur_groupno));
#endif
}
/** No descriptions */
void KBSwitchApp::slotPreferences(){
KBConfigDlg dlg(&m_kbconf);
TQObject::connect(&dlg, TQ_SIGNAL(okClicked()), m_trayicon, TQ_SLOT(slotUpdateIcons()));
TQObject::connect(&dlg, TQ_SIGNAL(applyClicked()), m_trayicon, TQ_SLOT(slotUpdateIcons()));
TQObject::connect(&dlg, TQ_SIGNAL(okClicked()), this, TQ_SLOT(slotPrefChanged()));
TQObject::connect(&dlg, TQ_SIGNAL(applyClicked()), this, TQ_SLOT(slotPrefChanged()));
dlg.exec();
}
/** Called when XKeyboard configuration changes */
void KBSwitchApp::reconfigure(){
m_kbconf.load(config());
m_trayicon->reconfigure();
// make sure default group is still valid
if (m_kbconf.default_groupno() >= m_xkb.getNumKbdGroups())
m_kbconf.set_default_groupno(0);
int groupno = m_xkb.getGroupNo();
if (groupno >= m_xkb.getNumKbdGroups()) {
// current group no longer valid, reset to default group
setStartGroup(m_kbconf.default_groupno());
}
else if (!m_force_group_setting) {
adaptToGroup(groupno);
}
#ifndef HAVE_LIBXKLAVIER
//resetWindowMap();
if (m_watcher) m_watcher->reset();
#endif
}
/** Respond to XKB changing the current group */
void KBSwitchApp::slotXkbGroupChanged(int groupno){
#ifdef HAVE_LIBXKLAVIER
updateIcon(groupno);
/* XWindowAttributes attrs;
XGetWindowAttributes(tqt_xdisplay(), tqt_xrootwin(), &attrs);
kdDebug() << "root event mask is " << attrs.your_event_mask << endl;
kdDebug() << "SubstructureNotifyMask is " <<
((attrs.your_event_mask & SubstructureNotifyMask) ? "ON" : "OFF") << endl;*/
#else
bool accept = false;
if (m_force_group_setting) { // the change of group is forced by us
if (groupno == m_cur_groupno) { // the group is what we wanted, fine
m_force_group_setting = false;
accept = true;
}
else { // oops, not the group we expected
forceSetGroup(m_cur_groupno);
}
}
else { // the change is caused by something external, we didn't request it
if (m_kbconf.toggle_mode() && groupno != m_next_groupno) { // toggle mode, and the group is not correct
m_xkb.setGroupNo(m_next_groupno);
}
else { // adjust to this group
if (m_kbconf.toggle_mode()) internalToggleGroups();
else {
m_cur_groupno = groupno;
m_next_groupno = m_kbconf.getNextGroup(groupno);
}
accept = true;
}
}
if (accept) {
updateIcon(groupno);
if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
}
/*if (m_kbconf.toggle_mode() && !force_group_setting && groupno != m_next_groupno) {
forceSetGroup(m_next_groupno);
}
else {
updateIcon(groupno);
force_group_setting = false;
if (m_kbconf.toggle_mode()) internalToggleGroups();
else {
kdDebug() << "slotXkbGroupChanged, change group to " << groupno << endl;
m_cur_groupno = groupno;
m_next_groupno = m_kbconf.getNextGroup(groupno);
}
if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
}*/
#endif
}
/** Set the keyboard to the given group and set internal variable accordingly */
void KBSwitchApp::setStartGroup(int start_group){
/*m_next_groupno = start_group;
if (m_kbconf.toggle_mode()) {
m_cur_groupno = getNextGroup(start_group);
}
else {
m_cur_groupno = start_group;
}
forceSetGroup(m_next_groupno);*/
setGroups(start_group, m_kbconf.getNextGroup(start_group));
}
/** adapt internal state to the given group */
void KBSwitchApp::adaptToGroup(int groupno) {
if (! m_kbconf.toggle_mode() || // if not in toggle mode
(m_cur_groupno != groupno // or in toggle mode and internal variables are invalid
|| m_next_groupno >= m_kbconf.groupCount()
|| m_next_groupno == m_cur_groupno)) {
m_cur_groupno = groupno;
m_next_groupno = m_kbconf.getNextGroup(groupno);
}
#ifndef HAVE_LIBXKLAVIER
if (m_watcher) m_watcher->changeGroup(groupno, m_next_groupno);
/*if (m_active_window != m_window_map.end()) {
m_active_window.data().groupno = groupno;
m_active_window.data().next_groupno = m_next_groupno;
}*/
#endif
updateIcon(groupno);
}
/*void KBSwitchApp::slotWindowChanged(WId activeWindow)
{
#ifndef HAVE_LIBXKLAVIER
m_active_window = m_window_map.find(activeWindow);
if (m_active_window == m_window_map.end())
addWindowToMap(activeWindow);
if (m_active_window.data().groupno != m_cur_groupno) {
setGroups(m_active_window.data().groupno, m_active_window.data().next_groupno);
}
else m_next_groupno = m_active_window.data().next_groupno;
#endif
}*/
void KBSwitchApp::slotWindowChanged(int groupno, int next_groupno)
{
if (groupno != m_cur_groupno) {
setGroups(groupno, next_groupno);
}
else m_next_groupno = next_groupno;
}
/*void KBSwitchApp::slotWindowRemoved(WId window)
{
#ifndef HAVE_LIBXKLAVIER
m_window_map.remove(window);
#endif
}
#ifndef HAVE_LIBXKLAVIER
void KBSwitchApp::resetWindowMap()
{
WId active_window_id;
m_window_map.clear();
if (m_twin_module && (active_window_id = m_twin_module->activeWindow()))
addWindowToMap(active_window_id);
else
m_active_window = m_window_map.end();
}*/
/** Enable window manager notifications */
/*void KBSwitchApp::enableKWinModule()
{
if (m_twin_module == NULL) {
m_twin_module = new KWinModule();
connect(m_twin_module, TQ_SIGNAL(activeWindowChanged(WId)), TQ_SLOT(slotWindowChanged(WId)));
connect(m_twin_module, TQ_SIGNAL(windowRemoved(WId)), TQ_SLOT(slotWindowRemoved(WId)));
resetWindowMap();
if (m_cur_groupno != -1 && m_cur_groupno != m_kbconf.default_groupno())
setStartGroup(m_kbconf.default_groupno());
}
}*/
/** Disable window manager notifications */
/*void KBSwitchApp::disableKWinModule()
{
if (m_twin_module) {
m_twin_module->disconnect();
delete m_twin_module;
m_twin_module = NULL;
resetWindowMap();
}
}*/
/** adds a new window to the internal window map */
/*void KBSwitchApp::addWindowToMap(WId window_id)
{
KBWinInfo wininfo = { m_kbconf.default_groupno(),
m_kbconf.getNextGroup(m_kbconf.default_groupno()) };
m_active_window = m_window_map.insert(window_id, wininfo);
}
#endif*/
void KBSwitchApp::enableWatcher()
{
if (!m_watcher) {
m_watcher_type = m_kbconf.group_scope();
if (m_watcher_type == KBConfig::SCOPE_WINDOW)
m_watcher = new SingleWindowWatcher(&m_kbconf, this);
else if (m_watcher_type == KBConfig::SCOPE_CLASS)
m_watcher = new WindowClassWatcher(&m_kbconf, this);
else return; // if scope is global, don't create watcher
connect(m_watcher, TQ_SIGNAL(windowChanged(int, int )),
TQ_SLOT(slotWindowChanged(int, int)));
}
}
void KBSwitchApp::disableWatcher()
{
if (m_watcher) {
m_watcher->disconnect();
delete m_watcher;
m_watcher = NULL;
}
}
/** React to a change in KKBSwitch's user preferences,
* made by user in Configure dialog */
void KBSwitchApp::slotPrefChanged()
{
#ifndef HAVE_LIBXKLAVIER
if (m_kbconf.group_scope() != m_watcher_type) {
disableWatcher();
enableWatcher();
}
#endif
}
/** Set the current and next groups */
void KBSwitchApp::setGroups(int group, int next_group)
{
m_cur_groupno = group;
m_next_groupno = next_group;
forceSetGroup(group);
}
#include "kbswitchapp.moc"