[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-panel-devel
Subject: Re: [Panel-devel] Plasma and the window manager (Re:
From: Jason Stubbs <jasonbstubbs () gmail ! com>
Date: 2007-11-23 11:58:31
Message-ID: 200711232058.31596.jasonbstubbs () gmail ! com
[Download RAW message or body]
On Friday 23 November 2007 19:13:38 Chani wrote:
> On November 23, 2007 17:23:10 Jason Stubbs wrote:
> > The patch is attached. I ended up cleaning up and/or simplifying more
> > than is necessary for reparenting, but it should still be fairly easy to
> > follow. There's current three issues that I know of:
>
> you removed a comment from the code for no apparent reason, and your own
> code has ZERO comments.
> please, please, comment your code. uncommented code makes baby jesus cry.
I'm more of the school that unreadable code make baby jesus cry. But I guess
my code wasn't readable enough, so I've gone through and commented everything
though. :)
> as for the code itself, I'm not sure, because I'm too tired to follow
> uncommented code - but several things look kinda suspicious, and some stuff
> is removed that maybe shouldn't be... for one thing, don't assume that
> you're going to get a clientClosed() signal. iirc, sometimes systray icons
> go away without bothering to tell the systray (scim was one, I think).
That was the only thing I wasn't sure would be safe to remove given the
comment that was previously there. However, testing `kill -9 $(pidof kmix)`
worked fine so I think it should be safe. Even with the current code, the
icon is going to hang around at least until something else causes a
clientClosed() so it's an issue either way.
--
Jason Stubbs
["systray-parenting.patch" (text/x-diff)]
Index: systemtray.cpp
===================================================================
--- systemtray.cpp (revision 740358)
+++ systemtray.cpp (working copy)
@@ -25,60 +25,122 @@
// KDE
#include <KWindowSystem>
-#include <QGraphicsView>
SystemTray::SystemTray(QObject *parent, const QVariantList &arguments)
- : Plasma::Applet(parent, arguments),
- m_systemTrayWidget(new SystemTrayWidget(0,
- Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint))
-{
- connect(m_systemTrayWidget, SIGNAL(sizeChanged()), SLOT(updateLayout()));
- m_systemTrayWidget->show();
- KWindowSystem::setState(m_systemTrayWidget->winId(),
- NET::SkipTaskbar | NET::SkipPager | NET::KeepBelow);
-}
+ : Plasma::Applet(parent, arguments)
+{ }
SystemTray::~SystemTray()
{
+ // Get rid of our SystemTrayWidget if we still have one
delete m_systemTrayWidget;
}
-QSizeF SystemTray::contentSizeHint() const
-{
- return QSizeF(m_systemTrayWidget->size());
-}
-
Qt::Orientations SystemTray::expandingDirections() const
{
- // simplify layouting by giving the system tray a fixed
- // size for now
+ // Extra space isn't useful in either direction
return 0;
}
QVariant SystemTray::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
- if (change == ItemPositionHasChanged) {
- //figure out where this applet really is.
- QPoint realPos(0, 0); //start with a default that's at least visible
- QGraphicsScene *s=scene();
- if (s) {
- QList<QGraphicsView *> viewlist = s->views();
- foreach (QGraphicsView *v, viewlist) {
- QRectF r=v->sceneRect();
- //now find out if this applet is actually on here
- //I consider it "on here" if our pos is within the rect
- //but there may be other valid ways to do this
- if (r.contains(scenePos())) {
- kDebug() << "using view" << v;
- QPoint p=v->mapFromScene(scenePos());
- realPos = v->mapToGlobal(p);
- break; //no, I don't care if other views show it
- }
- }
+ // We've been added to a scene
+ if (change == ItemSceneChange) {
+ // If we were previously part of a different scene,
+ // stop monitoring it for changes
+ if (m_currentScene) {
+ disconnect(m_currentScene, SIGNAL(changed(const QList<QRectF> &)),
+ this, SLOT(handleSceneChange(const QList<QRectF> &)));
}
- m_systemTrayWidget->move(realPos);
+ // Make a note of what scene we're on and start
+ // monitoring it for changes
+ // We need to monitor all changes because a QGraphicsItem normally
+ // only get notified of changes relative to its parent but we need
+ // to know about changes relative to the view to be able to correctly
+ // place our SystemTrayWidget
+ m_currentScene = value.value<QGraphicsScene *>();
+ if (m_currentScene) {
+ connect(m_currentScene, SIGNAL(changed(const QList<QRectF> &)),
+ this, SLOT(handleSceneChange(const QList<QRectF> &)));
+ }
}
return Plasma::Applet::itemChange(change, value);
}
+void SystemTray::handleSceneChange(const QList<QRectF> & region)
+{
+ // Don't do anything if none of the scene changes affect us
+ bool affected = false;
+ foreach (QRectF rect, region) {
+ if (rect.contains(scenePos())) {
+ affected = true;
+ break;
+ }
+ }
+ if (!affected) {
+ return;
+ }
+
+ // Find out which QGraphicsView (if any) that we are
+ // visible on
+ // We may be visible on more than one QGraphicsView but
+ // we only take the first because we are only able to
+ // display one system tray
+ QGraphicsView *view = 0;
+ foreach (view, m_currentScene->views()) {
+ if (view->sceneRect().contains(scenePos())) {
+ break;
+ }
+ view = 0;
+ }
+ if (!view) {
+ return;
+ }
+
+ // If the view is different to the view we were previously visible on
+ // or we had no view up until now, recreate our SystemTrayWidget
+ if (view != m_currentView) {
+ m_currentView = view;
+ // If the previous view still exists and is just not displaying us
+ // anymore, we need to delete the SystemTrayWidget that is parented
+ // to it
+ delete m_systemTrayWidget;
+ // Create a new SystemTrayWidget as a child of the current view and
+ // ask to be notified when it should change size
+ m_systemTrayWidget = new SystemTrayWidget(view);
+ m_systemTrayWidget->setVisible(true);
+ connect(m_systemTrayWidget, SIGNAL(sizeShouldChange()), this, SLOT(updateSize()));
+ }
+
+ // Set our SystemTrayWidget's size and position equal to that of this item
+ QRect rect = m_currentView->mapFromScene(sceneBoundingRect()).boundingRect();
+ m_systemTrayWidget->setGeometry(rect);
+}
+
+void SystemTray::updateSize()
+{
+ // We should always have a view if we're getting signals from a
+ // SystemTrayWidget but just in case...
+ if (!m_currentView) {
+ return;
+ }
+
+ // Get the minimum size allowed by our SystemTrayWidget
+ QRect widgetRect;
+ widgetRect.setSize(m_systemTrayWidget->minimumSizeHint());
+
+ // Transform the size into the coordinates used by our QGraphicsView
+ QSizeF newSize = m_currentView->mapToScene(widgetRect).boundingRect().size();
+
+ // If our minimum size is the same as same as our SystemTrayWidget's
+ // minimum size then we don't need to do anything
+ if (minimumSize() != newSize) {
+ // Otherwise, set our minimum size and inform the layout that
+ // things need to be adjusted accordingly
+ setMinimumSize(newSize);
+ resize(newSize);
+ updateGeometry();
+ }
+}
+
#include "systemtray.moc"
Index: systemtraywidget.cpp
===================================================================
--- systemtraywidget.cpp (revision 740358)
+++ systemtraywidget.cpp (working copy)
@@ -48,12 +48,16 @@
SystemTrayWidget::SystemTrayWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f)
{
- m_layout = new QHBoxLayout(this);
- setLayout(m_layout);
+ // TODO: Support vertical layout and multiple lines of icons
+ setLayout(new QHBoxLayout(this));
+
+ // FIXME: We should really use Qt::transparent, but it does not
+ // seem to be working with QX11EmbedContainer at the moment
QPalette newPalette = palette();
- newPalette.setBrush(QPalette::Window, Qt::black);
+ newPalette.setColor(QPalette::Window, Qt::black);
setPalette(newPalette);
- KWindowSystem::setState(winId(), NET::Sticky | NET::KeepAbove);
+ setBackgroundRole(QPalette::Window);
+
init();
}
@@ -62,7 +66,21 @@
if (event->type == ClientMessage) {
if (event->xclient.message_type == m_opcodeAtom &&
event->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
- embedWindow((WId)event->xclient.data.l[2]);
+ // Set up a new QX11EmbedContainer and embed the requested
+ // Window ID into it
+ QX11EmbedContainer *container = new QX11EmbedContainer(this);
+ container->embedClient((WId)event->xclient.data.l[2]);
+ // This minimizes flicker for the time being
+ container->setAutoFillBackground(false);
+ layout()->addWidget(container);
+
+ // Let the outside know that our size should change once the
+ // client has finished embedding or when the client closes
+ connect(container, SIGNAL(clientIsEmbedded()), this, SIGNAL(sizeShouldChange()));
+ connect(container, SIGNAL(clientClosed()), this, SIGNAL(sizeShouldChange()));
+ // When the client closes, also get rid of the container
+ connect(container, SIGNAL(clientClosed()), container, SLOT(deleteLater()));
+
return true;
}
}
@@ -95,51 +113,4 @@
}
}
-bool SystemTrayWidget::event(QEvent *event)
-{
- if (event->type() == QEvent::LayoutRequest) {
- resize(minimumSize());
- emit sizeChanged();
- }
- return QWidget::event(event);
-}
-
-void SystemTrayWidget::embedWindow(WId id)
-{
- kDebug() << "trying to add window with id " << id;
- if (! m_containers.contains(id)) {
- QX11EmbedContainer *container = new QX11EmbedContainer(this);
- container->embedClient(id);
- // TODO: add error handling
- m_layout->addWidget(container);
- container->show();
- m_containers[id] = container;
- connect(container, SIGNAL(clientClosed()), this, SLOT(windowClosed()) );
- kDebug() << "SystemTray: Window with id " << id << "added" << container;
- }
-}
-
-//what exactly is this for? is it related to QX11EmbedContainer::discardClient? why is it blank?
-void SystemTrayWidget::discardWindow(WId)
-{
-}
-
-void SystemTrayWidget::windowClosed()
-{
- kDebug() << "Window closed";
- //by this point the window id is gone, so we have to iterate to find out who's lost theirs
- ContainersList::iterator i = m_containers.begin();
- while (i != m_containers.end()) {
- QX11EmbedContainer *c=i.value();
- if (c->clientWinId()==0) {
- i=m_containers.erase(i);
- kDebug() << "deleting container" << c;
- delete c;
- //do NOT assume that there will never be more than one without an id
- continue;
- }
- ++i;
- }
-}
-
#include "systemtraywidget.moc"
Index: systemtray.h
===================================================================
--- systemtray.h (revision 740358)
+++ systemtray.h (working copy)
@@ -22,6 +22,11 @@
#ifndef SYSTEMTRAY_H
#define SYSTEMTRAY_H
+// Qt
+#include <QGraphicsScene>
+#include <QGraphicsView>
+#include <QPointer>
+
// Plasma
#include <plasma/applet.h>
@@ -35,19 +40,22 @@
SystemTray(QObject *parent, const QVariantList &arguments = QVariantList());
~SystemTray();
- QSizeF contentSizeHint() const;
-
Qt::Orientations expandingDirections() const;
protected:
QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value);
private slots:
- void updateLayout()
- { update(); }
+ void updateSize();
+ void handleSceneChange(const QList<QRectF> & region);
private:
- SystemTrayWidget *m_systemTrayWidget;
+ void initSystemTrayWidget(QWidget* parent);
+
+ // These can all be deleted externally so we guard them
+ QPointer<SystemTrayWidget> m_systemTrayWidget;
+ QPointer<QGraphicsScene> m_currentScene;
+ QPointer<QGraphicsView> m_currentView;
};
K_EXPORT_PLASMA_APPLET(systemtray, SystemTray)
Index: systemtraywidget.h
===================================================================
--- systemtraywidget.h (revision 740358)
+++ systemtraywidget.h (working copy)
@@ -24,13 +24,10 @@
// Qt
#include <QWidget>
-#include <QHash>
// Xlib
#include <X11/Xdefs.h>
-class QHBoxLayout;
-class QX11EmbedContainer;
class SystemTrayWidget: public QWidget
{
@@ -41,25 +38,15 @@
protected:
bool x11Event(XEvent *event);
- bool event(QEvent *event);
Q_SIGNALS:
- void sizeChanged();
+ void sizeShouldChange();
-private slots:
+private:
void init();
- void embedWindow(WId id);
- void discardWindow(WId id);
- /**
- * Removes the container with id 0 from our list.
- */
- void windowClosed();
private:
- typedef QHash<WId, QX11EmbedContainer*> ContainersList;
-
- ContainersList m_containers;
- QHBoxLayout *m_layout;
+ // These need to remain allocated for the duration of our lifetime
Atom m_selectionAtom;
Atom m_opcodeAtom;
};
_______________________________________________
Panel-devel mailing list
Panel-devel@kde.org
https://mail.kde.org/mailman/listinfo/panel-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic