summaryrefslogtreecommitdiffstats
path: root/kicker/applets/systemtray/systemtrayapplet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kicker/applets/systemtray/systemtrayapplet.cpp')
-rw-r--r--kicker/applets/systemtray/systemtrayapplet.cpp1223
1 files changed, 1223 insertions, 0 deletions
diff --git a/kicker/applets/systemtray/systemtrayapplet.cpp b/kicker/applets/systemtray/systemtrayapplet.cpp
new file mode 100644
index 000000000..41d5af10b
--- /dev/null
+++ b/kicker/applets/systemtray/systemtrayapplet.cpp
@@ -0,0 +1,1223 @@
+/*****************************************************************
+
+Copyright (c) 2000-2001 Matthias Ettrich <ettrich@kde.org>
+ 2000-2001 Matthias Elter <elter@kde.org>
+ 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+ 2001 Martijn Klingens <mklingens@yahoo.com>
+ 2004 Aaron J. Seigo <aseigo@kde.org>
+ 2010 Timothy Pearson <kb9vqf@pearsoncomputing.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <tqcursor.h>
+#include <tqpopupmenu.h>
+#include <tqtimer.h>
+#include <tqpixmap.h>
+#include <tqevent.h>
+#include <tqstyle.h>
+#include <tqgrid.h>
+#include <tqpainter.h>
+#include <tqimage.h>
+
+#include <dcopclient.h>
+#include <tdeapplication.h>
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <kdebug.h>
+#include <tdeglobal.h>
+#include <krun.h>
+#include <twinmodule.h>
+#include <kdialogbase.h>
+#include <tdeactionselector.h>
+#include <kiconloader.h>
+#include <twin.h>
+
+#include "kickerSettings.h"
+
+#include "simplebutton.h"
+
+#include "systemtrayapplet.h"
+#include "systemtrayapplet.moc"
+
+#include <X11/Xlib.h>
+
+#define ICON_MARGIN 1
+#define ICON_END_MARGIN KickerSettings::showDeepButtons()?4:0
+
+extern "C"
+{
+ KDE_EXPORT KPanelApplet* init(TQWidget *parent, const TQString& configFile)
+ {
+ TDEGlobal::locale()->insertCatalogue("ksystemtrayapplet");
+ return new SystemTrayApplet(configFile, KPanelApplet::Normal,
+ KPanelApplet::Preferences, parent, "ksystemtrayapplet");
+ }
+}
+
+SystemTrayApplet::SystemTrayApplet(const TQString& configFile, Type type, int actions,
+ TQWidget *parent, const char *name)
+ : KPanelApplet(configFile, type, actions, parent, name),
+ m_showFrame(KickerSettings::showDeepButtons()?true:false),
+ m_showHidden(false),
+ m_expandButton(0),
+ m_leftSpacer(0),
+ m_rightSpacer(0),
+ m_clockApplet(0),
+ m_settingsDialog(0),
+ m_iconSelector(0),
+ m_autoRetractTimer(0),
+ m_autoRetract(false),
+ m_iconSize(24),
+ m_showClockInTray(false),
+ m_showClockSettingCB(0),
+ m_layout(0)
+{
+ DCOPObject::setObjId("SystemTrayApplet");
+ loadSettings();
+
+ m_leftSpacer = new TQWidget(this);
+ m_leftSpacer->setFixedSize(ICON_END_MARGIN,1);
+ m_rightSpacer = new TQWidget(this);
+ m_rightSpacer->setFixedSize(ICON_END_MARGIN,1);
+
+ m_clockApplet = new ClockApplet(configFile, KPanelApplet::Normal, KPanelApplet::Preferences, this, "clockapplet");
+ updateClockGeometry();
+ connect(m_clockApplet, TQT_SIGNAL(clockReconfigured()), this, TQT_SLOT(updateClockGeometry()));
+
+ setBackgroundOrigin(AncestorOrigin);
+
+ twin_module = new KWinModule(TQT_TQOBJECT(this));
+
+ // kApplication notifies us of settings changes. added to support
+ // disabling of frame effect on mouse hover
+ kapp->dcopClient()->setNotifications(true);
+ connectDCOPSignal("kicker", "kicker", "configurationChanged()", "loadSettings()", false);
+
+ TQTimer::singleShot(0, this, TQT_SLOT(initialize()));
+}
+
+void SystemTrayApplet::updateClockGeometry()
+{
+ if (m_clockApplet)
+ m_clockApplet->setFixedSize(m_clockApplet->widthForHeight(height()-2),height()-2);
+}
+
+void SystemTrayApplet::initialize()
+{
+ // register existing tray windows
+ const TQValueList<WId> systemTrayWindows = twin_module->systemTrayWindows();
+ bool existing = false;
+ for (TQValueList<WId>::ConstIterator it = systemTrayWindows.begin();
+ it != systemTrayWindows.end(); ++it )
+ {
+ embedWindow(*it, true);
+ existing = true;
+ }
+
+ showExpandButton(!m_hiddenWins.isEmpty());
+
+ if (existing)
+ {
+ updateVisibleWins();
+ layoutTray();
+ }
+
+ // the KWinModule notifies us when tray windows are added or removed
+ connect( twin_module, TQT_SIGNAL( systemTrayWindowAdded(WId) ),
+ this, TQT_SLOT( systemTrayWindowAdded(WId) ) );
+ connect( twin_module, TQT_SIGNAL( systemTrayWindowRemoved(WId) ),
+ this, TQT_SLOT( updateTrayWindows() ) );
+
+ TQCString screenstr;
+ screenstr.setNum(tqt_xscreen());
+ TQCString trayatom = "_NET_SYSTEM_TRAY_S" + screenstr;
+
+ Display *display = tqt_xdisplay();
+
+ net_system_tray_selection = XInternAtom(display, trayatom, false);
+ net_system_tray_opcode = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", false);
+
+ // Acquire system tray
+ XSetSelectionOwner(display,
+ net_system_tray_selection,
+ winId(),
+ CurrentTime);
+
+ WId root = tqt_xrootwin();
+
+ if (XGetSelectionOwner (display, net_system_tray_selection) == winId())
+ {
+ XClientMessageEvent xev;
+
+ xev.type = ClientMessage;
+ xev.window = root;
+
+ xev.message_type = XInternAtom (display, "MANAGER", False);
+ xev.format = 32;
+ xev.data.l[0] = CurrentTime;
+ xev.data.l[1] = net_system_tray_selection;
+ xev.data.l[2] = winId();
+ xev.data.l[3] = 0; /* manager specific data */
+ xev.data.l[4] = 0; /* manager specific data */
+
+ XSendEvent (display, root, False, StructureNotifyMask, (XEvent *)&xev);
+ }
+
+ setBackground();
+}
+
+SystemTrayApplet::~SystemTrayApplet()
+{
+ for (TrayEmbedList::const_iterator it = m_hiddenWins.constBegin();
+ it != m_hiddenWins.constEnd();
+ ++it)
+ {
+ delete *it;
+ }
+
+ for (TrayEmbedList::const_iterator it = m_shownWins.constBegin();
+ it != m_shownWins.constEnd();
+ ++it)
+ {
+ delete *it;
+ }
+
+ if (m_leftSpacer) delete m_leftSpacer;
+ if (m_rightSpacer) delete m_rightSpacer;
+
+ TDEGlobal::locale()->removeCatalogue("ksystemtrayapplet");
+}
+
+bool SystemTrayApplet::x11Event( XEvent *e )
+{
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define SYSTEM_TRAY_BEGIN_MESSAGE 1
+#define SYSTEM_TRAY_CANCEL_MESSAGE 2
+ if ( e->type == ClientMessage ) {
+ if ( e->xclient.message_type == net_system_tray_opcode &&
+ e->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+ if( isWinManaged( (WId)e->xclient.data.l[2] ) ) // we already manage it
+ return true;
+ embedWindow( e->xclient.data.l[2], false );
+ updateVisibleWins();
+ layoutTray();
+ return true;
+ }
+ }
+ return KPanelApplet::x11Event( e ) ;
+}
+
+void SystemTrayApplet::preferences()
+{
+ if (m_settingsDialog)
+ {
+ m_settingsDialog->show();
+ m_settingsDialog->raise();
+ return;
+ }
+
+ m_settingsDialog = new KDialogBase(0, "systrayconfig",
+ false, i18n("Configure System Tray"),
+ KDialogBase::Ok | KDialogBase::Apply | KDialogBase::Cancel,
+ KDialogBase::Ok, true);
+ m_settingsDialog->resize(450, 400);
+ connect(m_settingsDialog, TQT_SIGNAL(applyClicked()), this, TQT_SLOT(applySettings()));
+ connect(m_settingsDialog, TQT_SIGNAL(okClicked()), this, TQT_SLOT(applySettings()));
+ connect(m_settingsDialog, TQT_SIGNAL(finished()), this, TQT_SLOT(settingsDialogFinished()));
+
+ TQGrid *settingsGrid = m_settingsDialog->makeGridMainWidget( 2, Qt::Vertical);
+
+ m_showClockSettingCB = new TQCheckBox(i18n("Show Clock in Tray"), settingsGrid);
+ m_showClockSettingCB->setChecked(m_showClockInTray);
+
+ //m_iconSelector = new TDEActionSelector(m_settingsDialog);
+ m_iconSelector = new TDEActionSelector(settingsGrid);
+ m_iconSelector->setAvailableLabel(i18n("Hidden icons:"));
+ m_iconSelector->setSelectedLabel(i18n("Visible icons:"));
+ //m_settingsDialog->setMainWidget(m_iconSelector);
+
+ TQListBox *hiddenListBox = m_iconSelector->availableListBox();
+ TQListBox *shownListBox = m_iconSelector->selectedListBox();
+
+ TrayEmbedList::const_iterator it = m_shownWins.begin();
+ TrayEmbedList::const_iterator itEnd = m_shownWins.end();
+ for (; it != itEnd; ++it)
+ {
+ TQString name = KWin::windowInfo((*it)->embeddedWinId()).name();
+ if(!shownListBox->findItem(name, TQt::ExactMatch | TQt::CaseSensitive))
+ {
+ shownListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name);
+ }
+ }
+
+ it = m_hiddenWins.begin();
+ itEnd = m_hiddenWins.end();
+ for (; it != itEnd; ++it)
+ {
+ TQString name = KWin::windowInfo((*it)->embeddedWinId()).name();
+ if(!hiddenListBox->findItem(name, TQt::ExactMatch | TQt::CaseSensitive))
+ {
+ hiddenListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name);
+ }
+ }
+
+ m_settingsDialog->show();
+}
+
+void SystemTrayApplet::settingsDialogFinished()
+{
+ m_settingsDialog->delayedDestruct();
+ m_settingsDialog = 0;
+ m_iconSelector = 0;
+}
+
+void SystemTrayApplet::applySettings()
+{
+ if (!m_iconSelector)
+ {
+ return;
+ }
+
+ m_showClockInTray = m_showClockSettingCB->isChecked();
+
+ TDEConfig *conf = config();
+
+ // Save the sort order and hidden status using the window class (WM_CLASS) rather
+ // than window name (caption) - window name is i18n-ed, so it's for example
+ // not possible to create default settings.
+ // For backwards compatibility, name is kept as it is, class is preceded by '!'.
+ TQMap< TQString, TQString > windowNameToClass;
+ for( TrayEmbedList::ConstIterator it = m_shownWins.begin();
+ it != m_shownWins.end();
+ ++it ) {
+ KWin::WindowInfo info = KWin::windowInfo( (*it)->embeddedWinId(), NET::WMName, NET::WM2WindowClass);
+ windowNameToClass[ info.name() ] = '!' + info.windowClassClass();
+ }
+ for( TrayEmbedList::ConstIterator it = m_hiddenWins.begin();
+ it != m_hiddenWins.end();
+ ++it ) {
+ KWin::WindowInfo info = KWin::windowInfo( (*it)->embeddedWinId(), NET::WMName, NET::WM2WindowClass);
+ windowNameToClass[ info.name() ] = '!' + info.windowClassClass();
+ }
+
+ conf->setGroup("SortedTrayIcons");
+ m_sortOrderIconList.clear();
+ for(TQListBoxItem* item = m_iconSelector->selectedListBox()->firstItem();
+ item;
+ item = item->next())
+ {
+ if( windowNameToClass.contains(item->text()))
+ m_sortOrderIconList.append(windowNameToClass[item->text()]);
+ else
+ m_sortOrderIconList.append(item->text());
+ }
+ conf->writeEntry("SortOrder", m_sortOrderIconList);
+
+ conf->setGroup("HiddenTrayIcons");
+ m_hiddenIconList.clear();
+ for(TQListBoxItem* item = m_iconSelector->availableListBox()->firstItem();
+ item;
+ item = item->next())
+ {
+ if( windowNameToClass.contains(item->text()))
+ m_hiddenIconList.append(windowNameToClass[item->text()]);
+ else
+ m_hiddenIconList.append(item->text());
+ }
+ conf->writeEntry("Hidden", m_hiddenIconList);
+
+ conf->setGroup("System Tray");
+ conf->writeEntry("ShowClockInTray", m_showClockInTray);
+
+ conf->sync();
+
+ TrayEmbedList::iterator it = m_shownWins.begin();
+ while (it != m_shownWins.end())
+ {
+ if (shouldHide((*it)->embeddedWinId()))
+ {
+ m_hiddenWins.append(*it);
+ it = m_shownWins.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ it = m_hiddenWins.begin();
+ while (it != m_hiddenWins.end())
+ {
+ if (!shouldHide((*it)->embeddedWinId()))
+ {
+ m_shownWins.append(*it);
+ it = m_hiddenWins.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ showExpandButton(!m_hiddenWins.isEmpty());
+
+ updateVisibleWins();
+ layoutTray();
+}
+
+void SystemTrayApplet::checkAutoRetract()
+{
+ if (!m_autoRetractTimer)
+ {
+ return;
+ }
+
+ if (!geometry().contains(mapFromGlobal(TQCursor::pos())))
+ {
+ m_autoRetractTimer->stop();
+ if (m_autoRetract)
+ {
+ m_autoRetract = false;
+
+ if (m_showHidden)
+ {
+ retract();
+ }
+ }
+ else
+ {
+ m_autoRetract = true;
+ m_autoRetractTimer->start(2000, true);
+ }
+
+ }
+ else
+ {
+ m_autoRetract = false;
+ m_autoRetractTimer->start(250, true);
+ }
+}
+
+void SystemTrayApplet::showExpandButton(bool show)
+{
+ if (show)
+ {
+ if (!m_expandButton)
+ {
+ m_expandButton = new SimpleArrowButton(this, Qt::UpArrow, 0, KickerSettings::showDeepButtons());
+ m_expandButton->installEventFilter(this);
+ refreshExpandButton();
+
+ if (orientation() == Qt::Vertical)
+ {
+ m_expandButton->setFixedSize(width() - 4,
+ m_expandButton->sizeHint()
+ .height());
+ }
+ else
+ {
+ m_expandButton->setFixedSize(m_expandButton->sizeHint()
+ .width(),
+ height() - 4);
+ }
+ connect(m_expandButton, TQT_SIGNAL(clicked()),
+ this, TQT_SLOT(toggleExpanded()));
+
+ m_autoRetractTimer = new TQTimer(this, "m_autoRetractTimer");
+ connect(m_autoRetractTimer, TQT_SIGNAL(timeout()),
+ this, TQT_SLOT(checkAutoRetract()));
+ }
+ else
+ {
+ refreshExpandButton();
+ }
+
+ m_expandButton->show();
+ }
+ else if (m_expandButton)
+ {
+ m_expandButton->hide();
+ }
+}
+
+void SystemTrayApplet::orientationChange( Orientation /*orientation*/ )
+{
+ refreshExpandButton();
+}
+
+void SystemTrayApplet::iconSizeChanged() {
+ loadSettings();
+ updateVisibleWins();
+ layoutTray();
+
+ TrayEmbedList::iterator emb = m_shownWins.begin();
+ while (emb != m_shownWins.end()) {
+ (*emb)->setFixedSize(m_iconSize, m_iconSize);
+ ++emb;
+ }
+
+ emb = m_hiddenWins.begin();
+ while (emb != m_hiddenWins.end()) {
+ (*emb)->setFixedSize(m_iconSize, m_iconSize);
+ ++emb;
+ }
+}
+
+void SystemTrayApplet::loadSettings()
+{
+ // set our defaults
+ setFrameStyle(NoFrame);
+ m_showFrame = KickerSettings::showDeepButtons()?true:false;
+
+ TDEConfig *conf = config();
+ conf->reparseConfiguration();
+ conf->setGroup("General");
+
+ if (conf->readBoolEntry("ShowPanelFrame", false) || m_showFrame) // Does ShowPanelFrame even exist?
+ {
+ setFrameStyle(Panel | Sunken);
+ }
+
+ conf->setGroup("HiddenTrayIcons");
+ m_hiddenIconList = conf->readListEntry("Hidden");
+
+ conf->setGroup("SortedTrayIcons");
+ m_sortOrderIconList = conf->readListEntry("SortOrder");
+
+ //Note This setting comes from kdeglobal.
+ conf->setGroup("System Tray");
+ m_iconSize = conf->readNumEntry("systrayIconWidth", 22);
+ m_showClockInTray = conf->readNumEntry("ShowClockInTray", false);
+}
+
+void SystemTrayApplet::systemTrayWindowAdded( WId w )
+{
+ if (isWinManaged(w))
+ {
+ // we already manage it
+ return;
+ }
+
+ embedWindow(w, true);
+ updateVisibleWins();
+ layoutTray();
+
+ if (m_showFrame && frameStyle() == NoFrame)
+ {
+ setFrameStyle(Panel|Sunken);
+ }
+}
+
+void SystemTrayApplet::embedWindow( WId w, bool kde_tray )
+{
+ TrayEmbed* emb = new TrayEmbed(kde_tray, this);
+ emb->setAutoDelete(false);
+
+ if (kde_tray)
+ {
+ static Atom hack_atom = XInternAtom( tqt_xdisplay(), "_TDE_SYSTEM_TRAY_EMBEDDING", False );
+ XChangeProperty( tqt_xdisplay(), w, hack_atom, hack_atom, 32, PropModeReplace, NULL, 0 );
+ emb->embed(w);
+ XDeleteProperty( tqt_xdisplay(), w, hack_atom );
+ }
+ else
+ {
+ emb->embed(w);
+ }
+
+ if (emb->embeddedWinId() == 0) // error embedding
+ {
+ delete emb;
+ return;
+ }
+
+ connect(emb, TQT_SIGNAL(embeddedWindowDestroyed()), TQT_SLOT(updateTrayWindows()));
+ emb->getIconSize(m_iconSize);
+
+ if (shouldHide(w))
+ {
+ emb->hide();
+ m_hiddenWins.append(emb);
+ showExpandButton(true);
+ }
+ else
+ {
+ //emb->hide();
+ emb->setBackground();
+ emb->show();
+ m_shownWins.append(emb);
+ }
+}
+
+bool SystemTrayApplet::isWinManaged(WId w)
+{
+ TrayEmbedList::const_iterator lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb)
+ {
+ if ((*emb)->embeddedWinId() == w) // we already manage it
+ {
+ return true;
+ }
+ }
+
+ lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb)
+ {
+ if ((*emb)->embeddedWinId() == w) // we already manage it
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool SystemTrayApplet::shouldHide(WId w)
+{
+ return m_hiddenIconList.find(KWin::windowInfo(w).name()) != m_hiddenIconList.end()
+ || m_hiddenIconList.find('!'+KWin::windowInfo(w,0,NET::WM2WindowClass).windowClassClass())
+ != m_hiddenIconList.end();
+}
+
+void SystemTrayApplet::updateVisibleWins()
+{
+ TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end();
+ TrayEmbedList::const_iterator emb = m_hiddenWins.begin();
+
+ if (m_showHidden)
+ {
+ for (; emb != lastEmb; ++emb)
+ {
+ (*emb)->setBackground();
+ (*emb)->show();
+ }
+ }
+ else
+ {
+ for (; emb != lastEmb; ++emb)
+ {
+ (*emb)->hide();
+ }
+ }
+
+ TQMap< QXEmbed*, TQString > names; // cache window names and classes
+ TQMap< QXEmbed*, TQString > classes;
+ for( TrayEmbedList::const_iterator it = m_shownWins.begin();
+ it != m_shownWins.end();
+ ++it ) {
+ KWin::WindowInfo info = KWin::windowInfo((*it)->embeddedWinId(),NET::WMName,NET::WM2WindowClass);
+ names[ *it ] = info.name();
+ classes[ *it ] = '!'+info.windowClassClass();
+ }
+ TrayEmbedList newList;
+ for( TQStringList::const_iterator it1 = m_sortOrderIconList.begin();
+ it1 != m_sortOrderIconList.end();
+ ++it1 ) {
+ for( TrayEmbedList::iterator it2 = m_shownWins.begin();
+ it2 != m_shownWins.end();
+ ) {
+ if( (*it1).startsWith("!") ? classes[ *it2 ] == *it1 : names[ *it2 ] == *it1 ) {
+ newList.append( *it2 ); // don't bail out, there may be multiple ones
+ it2 = m_shownWins.erase( it2 );
+ } else
+ ++it2;
+ }
+ }
+ for( TrayEmbedList::const_iterator it = m_shownWins.begin();
+ it != m_shownWins.end();
+ ++it )
+ newList.append( *it ); // append unsorted items
+ m_shownWins = newList;
+}
+
+void SystemTrayApplet::toggleExpanded()
+{
+ if (m_showHidden)
+ {
+ retract();
+ }
+ else
+ {
+ expand();
+ }
+}
+
+void SystemTrayApplet::refreshExpandButton()
+{
+ if (!m_expandButton)
+ {
+ return;
+ }
+
+ Qt::ArrowType a;
+
+ if (orientation() == Qt::Vertical)
+ a = m_showHidden ? Qt::DownArrow : Qt::UpArrow;
+ else
+ a = (m_showHidden ^ kapp->reverseLayout()) ? Qt::RightArrow : Qt::LeftArrow;
+
+ m_expandButton->setArrowType(a);
+}
+
+void SystemTrayApplet::expand()
+{
+ m_showHidden = true;
+ refreshExpandButton();
+
+ updateVisibleWins();
+ layoutTray();
+
+ if (m_autoRetractTimer)
+ {
+ m_autoRetractTimer->start(250, true);
+ }
+}
+
+void SystemTrayApplet::retract()
+{
+ if (m_autoRetractTimer)
+ {
+ m_autoRetractTimer->stop();
+ }
+
+ m_showHidden = false;
+ refreshExpandButton();
+
+ updateVisibleWins();
+ layoutTray();
+}
+
+void SystemTrayApplet::updateTrayWindows()
+{
+ TrayEmbedList::iterator emb = m_shownWins.begin();
+ while (emb != m_shownWins.end())
+ {
+ WId wid = (*emb)->embeddedWinId();
+ if ((wid == 0) ||
+ ((*emb)->kdeTray() &&
+ !twin_module->systemTrayWindows().contains(wid)))
+ {
+ (*emb)->deleteLater();
+ emb = m_shownWins.erase(emb);
+ }
+ else
+ {
+ ++emb;
+ }
+ }
+
+ emb = m_hiddenWins.begin();
+ while (emb != m_hiddenWins.end())
+ {
+ WId wid = (*emb)->embeddedWinId();
+ if ((wid == 0) ||
+ ((*emb)->kdeTray() &&
+ !twin_module->systemTrayWindows().contains(wid)))
+ {
+ (*emb)->deleteLater();
+ emb = m_hiddenWins.erase(emb);
+ }
+ else
+ {
+ ++emb;
+ }
+ }
+
+ showExpandButton(!m_hiddenWins.isEmpty());
+ updateVisibleWins();
+ layoutTray();
+}
+
+int SystemTrayApplet::maxIconWidth() const
+{
+ int largest = m_iconSize;
+
+ TrayEmbedList::const_iterator lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb)
+ {
+ if (*emb == 0)
+ {
+ continue;
+ }
+
+ int width = (*emb)->width();
+ if (width > largest)
+ {
+ largest = width;
+ }
+ }
+
+ if (m_showHidden)
+ {
+ lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb)
+ {
+ int width = (*emb)->width();
+ if (width > largest)
+ {
+ largest = width;
+ }
+ }
+ }
+
+ return largest;
+}
+
+int SystemTrayApplet::maxIconHeight() const
+{
+ int largest = m_iconSize;
+
+ TrayEmbedList::const_iterator lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != m_shownWins.end(); ++emb)
+ {
+ if (*emb == 0)
+ {
+ continue;
+ }
+
+ int height = (*emb)->height();
+ if (height > largest)
+ {
+ largest = height;
+ }
+ }
+
+ if (m_showHidden)
+ {
+ lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != m_hiddenWins.end(); ++emb)
+ {
+ if (*emb == 0)
+ {
+ continue;
+ }
+
+ int height = (*emb)->height();
+ if (height > largest)
+ {
+ largest = height;
+ }
+ }
+ }
+
+ return largest;
+}
+
+bool SystemTrayApplet::eventFilter(TQObject* watched, TQEvent* e)
+{
+ if (TQT_BASE_OBJECT(watched) == TQT_BASE_OBJECT(m_expandButton))
+ {
+ TQPoint p;
+ if (e->type() == TQEvent::ContextMenu)
+ {
+ p = TQT_TQCONTEXTMENUEVENT(e)->globalPos();
+ }
+ else if (e->type() == TQEvent::MouseButtonPress)
+ {
+ TQMouseEvent* me = TQT_TQMOUSEEVENT(e);
+ if (me->button() == Qt::RightButton)
+ {
+ p = me->globalPos();
+ }
+ }
+
+ if (!p.isNull())
+ {
+ TQPopupMenu* contextMenu = new TQPopupMenu(this);
+ contextMenu->insertItem(SmallIcon("configure"), i18n("Configure System Tray..."),
+ this, TQT_SLOT(configure()));
+
+ contextMenu->exec(TQT_TQCONTEXTMENUEVENT(e)->globalPos());
+
+ delete contextMenu;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int SystemTrayApplet::widthForHeight(int h) const
+{
+ if (orientation() == Qt::Vertical)
+ {
+ return width();
+ }
+
+ int currentHeight = height();
+ if (currentHeight != h)
+ {
+ SystemTrayApplet* me = const_cast<SystemTrayApplet*>(this);
+ me->setMinimumSize(0, 0);
+ me->setMaximumSize(32767, 32767);
+ me->setFixedHeight(h);
+ }
+
+ return sizeHint().width();
+}
+
+int SystemTrayApplet::heightForWidth(int w) const
+{
+ if (orientation() == Qt::Horizontal)
+ {
+ return height();
+ }
+
+ int currentWidth = width();
+ if (currentWidth != w)
+ {
+ SystemTrayApplet* me = const_cast<SystemTrayApplet*>(this);
+ me->setMinimumSize(0, 0);
+ me->setMaximumSize(32767, 32767);
+ me->setFixedWidth(w);
+ }
+
+ return sizeHint().height();
+}
+
+void SystemTrayApplet::moveEvent( TQMoveEvent* )
+{
+ setBackground();
+}
+
+
+void SystemTrayApplet::resizeEvent( TQResizeEvent* )
+{
+ layoutTray();
+ // we need to give ourselves a chance to adjust our size before calling this
+ TQTimer::singleShot(0, this, TQT_SIGNAL(updateLayout()));
+}
+
+void SystemTrayApplet::layoutTray()
+{
+ setUpdatesEnabled(false);
+
+ int iconCount = m_shownWins.count();
+
+ if (m_showHidden)
+ {
+ iconCount += m_hiddenWins.count();
+ }
+
+ /* heightWidth = height or width in pixels (depends on orientation())
+ * nbrOfLines = number of rows or cols (depends on orientation())
+ * line = what line to draw an icon in */
+ int i = 0, line, nbrOfLines, heightWidth;
+ bool showExpandButton = m_expandButton && m_expandButton->isVisibleTo(this);
+ delete m_layout;
+ m_layout = new TQGridLayout(this, 1, 1, ICON_MARGIN, ICON_MARGIN);
+
+ if (m_expandButton)
+ {
+ if (orientation() == Qt::Vertical)
+ {
+ m_expandButton->setFixedSize(width() - 4, m_expandButton->sizeHint().height());
+ }
+ else
+ {
+ m_expandButton->setFixedSize(m_expandButton->sizeHint().width(), height() - 4);
+ }
+ }
+
+ // col = column or row, depends on orientation(),
+ // the opposite direction of line
+ int col = 0;
+
+ //
+ // The margin and spacing specified in the layout implies that:
+ // [-- ICON_MARGIN pixels --] [-- first icon --] [-- ICON_MARGIN pixels --] ... [-- ICON_MARGIN pixels --] [-- last icon --] [-- ICON_MARGIN pixels --]
+ //
+ // So, if we say that iconWidth is the icon width plus the ICON_MARGIN pixels spacing, then the available width for the icons
+ // is the widget width minus ICON_MARGIN pixels margin. Forgetting these ICON_MARGIN pixels broke the layout algorithm in KDE <= 3.5.9.
+ //
+ // This fix makes the workarounds in the heightForWidth() and widthForHeight() methods unneeded.
+ //
+
+ if (orientation() == Qt::Vertical)
+ {
+ int iconWidth = maxIconWidth() + ICON_MARGIN; // +2 for the margins that implied by the layout
+ heightWidth = width() - ICON_MARGIN;
+ // to avoid nbrOfLines=0 we ensure heightWidth >= iconWidth!
+ heightWidth = heightWidth < iconWidth ? iconWidth : heightWidth;
+ nbrOfLines = heightWidth / iconWidth;
+
+ m_layout->addMultiCellWidget(m_leftSpacer,
+ 0, 0,
+ 0, nbrOfLines - 1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ col = 1;
+
+ if (showExpandButton)
+ {
+ m_layout->addMultiCellWidget(m_expandButton,
+ 1, 1,
+ 0, nbrOfLines - 1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ col = 2;
+ }
+
+ if (m_showHidden)
+ {
+ TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin();
+ emb != lastEmb; ++emb)
+ {
+ line = i % nbrOfLines;
+ (*emb)->show();
+ m_layout->addWidget((*emb), col, line,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if ((line + 1) == nbrOfLines)
+ {
+ ++col;
+ }
+
+ ++i;
+ }
+ }
+
+ TrayEmbedList::const_iterator lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin();
+ emb != lastEmb; ++emb)
+ {
+ line = i % nbrOfLines;
+ (*emb)->show();
+ m_layout->addWidget((*emb), col, line,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if ((line + 1) == nbrOfLines)
+ {
+ ++col;
+ }
+
+ ++i;
+ }
+
+ m_layout->addMultiCellWidget(m_rightSpacer,
+ col, col,
+ 0, nbrOfLines - 1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if (m_clockApplet) {
+ if (m_showClockInTray)
+ m_clockApplet->show();
+ else
+ m_clockApplet->hide();
+
+ m_layout->addMultiCellWidget(m_clockApplet,
+ col+1, col+1,
+ 0, nbrOfLines - 1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ }
+ }
+ else // horizontal
+ {
+ int iconHeight = maxIconHeight() + ICON_MARGIN; // +2 for the margins that implied by the layout
+ heightWidth = height() - ICON_MARGIN;
+ heightWidth = heightWidth < iconHeight ? iconHeight : heightWidth; // to avoid nbrOfLines=0
+ nbrOfLines = heightWidth / iconHeight;
+
+ m_layout->addMultiCellWidget(m_leftSpacer,
+ 0, nbrOfLines - 1,
+ 0, 0,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ col = 1;
+
+ if (showExpandButton)
+ {
+ m_layout->addMultiCellWidget(m_expandButton,
+ 0, nbrOfLines - 1,
+ 1, 1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ col = 2;
+ }
+
+ if (m_showHidden)
+ {
+ TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb)
+ {
+ line = i % nbrOfLines;
+ (*emb)->show();
+ m_layout->addWidget((*emb), line, col,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if ((line + 1) == nbrOfLines)
+ {
+ ++col;
+ }
+
+ ++i;
+ }
+ }
+
+ TrayEmbedList::const_iterator lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin();
+ emb != lastEmb; ++emb)
+ {
+ line = i % nbrOfLines;
+ (*emb)->show();
+ m_layout->addWidget((*emb), line, col,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if ((line + 1) == nbrOfLines)
+ {
+ ++col;
+ }
+
+ ++i;
+ }
+
+ m_layout->addMultiCellWidget(m_rightSpacer,
+ 0, nbrOfLines - 1,
+ col, col,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+
+ if (m_clockApplet) {
+ if (m_showClockInTray)
+ m_clockApplet->show();
+ else
+ m_clockApplet->hide();
+
+ m_layout->addMultiCellWidget(m_clockApplet,
+ 0, nbrOfLines - 1,
+ col+1, col+1,
+ Qt::AlignHCenter | Qt::AlignVCenter);
+ }
+ }
+
+ setUpdatesEnabled(true);
+ updateGeometry();
+ setBackground();
+
+ updateClockGeometry();
+}
+
+void SystemTrayApplet::paletteChange(const TQPalette & /* oldPalette */)
+{
+ setBackground();
+}
+
+void SystemTrayApplet::setBackground()
+{
+ TrayEmbedList::const_iterator lastEmb;
+
+ lastEmb = m_shownWins.end();
+ for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb)
+ (*emb)->setBackground();
+
+ lastEmb = m_hiddenWins.end();
+ for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb)
+ (*emb)->setBackground();
+}
+
+
+TrayEmbed::TrayEmbed( bool kdeTray, TQWidget* parent )
+ : QXEmbed( parent ), kde_tray( kdeTray )
+{
+ hide();
+ m_scaledWidget = new TQWidget(parent);
+ m_scaledWidget->hide();
+}
+
+TrayEmbed::~TrayEmbed()
+{
+ //
+}
+
+void TrayEmbed::getIconSize(int defaultIconSize)
+{
+ TQSize minSize = minimumSizeHint();
+
+ int width = minSize.width();
+ int height = minSize.height();
+
+ if (width < 1 || width > defaultIconSize)
+ width = defaultIconSize;
+ if (height < 1 || height > defaultIconSize)
+ height = defaultIconSize;
+
+ setFixedSize(width, height);
+ setBackground();
+}
+
+void TrayEmbed::setBackground()
+{
+ const TQPixmap *pbg = parentWidget()->backgroundPixmap();
+
+ if (pbg) {
+ TQPixmap bg(width(), height());
+ bg.fill(parentWidget(), pos());
+ setPaletteBackgroundPixmap(bg);
+ setBackgroundOrigin(WidgetOrigin);
+ }
+ else {
+ unsetPalette();
+ }
+
+ if (!isHidden())
+ {
+ XClearArea(x11Display(), embeddedWinId(), 0, 0, 0, 0, True);
+ ensureBackgroundSet();
+ }
+}
+
+void TrayEmbed::ensureBackgroundSet()
+{
+ XWindowAttributes winprops;
+ XGetWindowAttributes(x11Display(), embeddedWinId(), &winprops);
+ if (winprops.depth == 32) {
+ // This is a nasty little hack to make sure that tray icons / applications which do not match our QXEmbed native depth are still displayed properly,
+ // i.e without irritating white/grey borders where the tray icon's transparency is supposed to be...
+ // Essentially it converts a 24 bit Xlib Pixmap to a 32 bit Xlib Pixmap
+
+ TQPixmap bg(width(), height());
+
+ // Get the RGB background image
+ bg.fill(parentWidget(), pos());
+ TQImage bgImage = bg.convertToImage();
+
+ // Create the ARGB pixmap
+ Pixmap argbpixmap = XCreatePixmap(x11Display(), embeddedWinId(), width(), height(), 32);
+ GC gc;
+ gc = XCreateGC(x11Display(), embeddedWinId(), 0, 0);
+ int w = bgImage.width();
+ int h = bgImage.height();
+ for (int y = 0; y < h; ++y) {
+ TQRgb *ls = (TQRgb *)bgImage.scanLine( y );
+ for (int x = 0; x < w; ++x) {
+ TQRgb l = ls[x];
+ int r = int( tqRed( l ) );
+ int g = int( tqGreen( l ) );
+ int b = int( tqBlue( l ) );
+ int a = int( tqAlpha( l ) );
+ XSetForeground(x11Display(), gc, (a << 24) | (r << 16) | (g << 8) | b );
+ XDrawPoint(x11Display(), argbpixmap, gc, x, y);
+ }
+ }
+ XFlush(x11Display());
+ XSetWindowBackgroundPixmap(x11Display(), embeddedWinId(), argbpixmap);
+ XFreePixmap(x11Display(), argbpixmap);
+ XFreeGC(x11Display(), gc);
+
+ // Repaint
+ XClearArea(x11Display(), embeddedWinId(), 0, 0, 0, 0, True);
+ }
+}