diff options
author | Ken Moore <moorekou@gmail.com> | 2016-04-25 13:08:12 -0400 |
---|---|---|
committer | Ken Moore <moorekou@gmail.com> | 2016-04-25 13:08:12 -0400 |
commit | ed5ecf7ea7a482b4649e66ecb35fbc60af680684 (patch) | |
tree | acc0fa17d228259e847f55c678db9fb0a9b50f0c /src-qt5/core/lumina-desktop/panel-plugins/systemtray | |
parent | Merge branch 'master' of github.com:pcbsd/lumina (diff) | |
download | lumina-ed5ecf7ea7a482b4649e66ecb35fbc60af680684.tar.gz lumina-ed5ecf7ea7a482b4649e66ecb35fbc60af680684.tar.bz2 lumina-ed5ecf7ea7a482b4649e66ecb35fbc60af680684.zip |
Rearrange the Lumina source tree quite a bit:
Now the utilites are arranged by category (core, core-utils, desktop-utils), so all the -utils may be excluded by a package system (or turned into separate packages) as needed.
Diffstat (limited to 'src-qt5/core/lumina-desktop/panel-plugins/systemtray')
4 files changed, 420 insertions, 0 deletions
diff --git a/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp new file mode 100644 index 00000000..b6af4451 --- /dev/null +++ b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp @@ -0,0 +1,164 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2012-2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "LSysTray.h" +#include "../../LSession.h" + +LSysTray::LSysTray(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){ + frame = new QFrame(this); + frame->setContentsMargins(0,0,0,0); + //frame->setStyleSheet("QFrame{ background: transparent; border: 1px solid transparent; border-radius: 3px; }"); + LI = new QBoxLayout( this->layout()->direction()); + frame->setLayout(LI); + LI->setAlignment(Qt::AlignCenter); + LI->setSpacing(0); + LI->setContentsMargins(0,0,0,0); + this->layout()->addWidget(frame); + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + //TrayID=0; + upTimer = new QTimer(this); + upTimer->setInterval(300000); //maximum time between refreshes is 5 minutes + connect(upTimer, SIGNAL(timeout()), this, SLOT(checkAll()) ); + isRunning = false; stopping = false; checking = false; pending = false; + QTimer::singleShot(100, this, SLOT(start()) ); + //Also do one extra check a minute or so after startup (just in case something got missed in the initial flood of registrations) + QTimer::singleShot(90000,this, SLOT(checkAll()) ); + connect(LSession::handle(), SIGNAL(TrayListChanged()), this, SLOT(checkAll()) ); + connect(LSession::handle(), SIGNAL(TrayIconChanged(WId)), this, SLOT(UpdateTrayWindow(WId)) ); + connect(LSession::handle(), SIGNAL(VisualTrayAvailable()), this, SLOT(start()) ); +} + +LSysTray::~LSysTray(){ + if(isRunning){ + this->stop(); + } +} + +void LSysTray::start(){ + if(isRunning || stopping){ return; } //already running + isRunning = LSession::handle()->registerVisualTray(this->winId()); + qDebug() << "Visual Tray Started:" << this->type() << isRunning; + if(isRunning){ + //upTimer->start(); + QTimer::singleShot(0,this, SLOT(checkAll()) ); + } +} + +void LSysTray::stop(){ + if(!isRunning){ return; } + stopping = true; + upTimer->stop(); + //Now close down the system tray registry + qDebug() << "Stop visual system tray:" << this->type(); + //LX11::closeSystemTray(TrayID); + //TrayID = 0; + disconnect(this); //remove any signals/slots + isRunning = false; + //Release all the tray applications and delete the containers + if( !LSession::handle()->currentTrayApps(this->winId()).isEmpty() ){ + qDebug() << " - Remove tray applications"; + //This overall system tray is not closed down - go ahead and release them here + for(int i=(trayIcons.length()-1); i>=0; i--){ + trayIcons[i]->detachApp(); + TrayIcon *cont = trayIcons.takeAt(i); + LI->removeWidget(cont); + cont->deleteLater(); + } + } + //Now let some other visual tray take over + LSession::handle()->unregisterVisualTray(this->winId()); + qDebug() << "Done stopping visual tray"; +} + +// ======================== +// PRIVATE FUNCTIONS +// ======================== +void LSysTray::checkAll(){ + if(!isRunning || stopping || checking){ pending = true; return; } //Don't check if not running at the moment + checking = true; + pending = false; + //Make sure this tray should handle the windows (was not disabled in the backend) + bool TrayRunning = LSession::handle()->registerVisualTray(this->winId()); + //qDebug() << "System Tray: Check tray apps"; + QList<WId> wins = LSession::handle()->currentTrayApps(this->winId()); + for(int i=0; i<trayIcons.length(); i++){ + int index = wins.indexOf(trayIcons[i]->appID()); + if(index < 0){ + //Tray Icon no longer exists: remove it + qDebug() << " - Visual System Tray: Remove Icon:" << trayIcons[i]->appID(); + TrayIcon *cont = trayIcons.takeAt(i); + cont->cleanup(); + LI->removeWidget(cont); + cont->deleteLater(); + i--; //List size changed + //Re-adjust the maximum widget size to account for what is left + if(this->layout()->direction()==QBoxLayout::LeftToRight){ + this->setMaximumSize( trayIcons.length()*this->height(), 10000); + }else{ + this->setMaximumSize(10000, trayIcons.length()*this->width()); + } + }else{ + //Tray Icon already exists + //qDebug() << " - SysTray: Update Icon"; + trayIcons[i]->update(); + wins.removeAt(index); //Already found - remove from the list + } + } + //Now go through any remaining windows and add them + for(int i=0; i<wins.length() && TrayRunning; i++){ + qDebug() << " - Visual System Tray: Add Icon:" << wins[i]; + TrayIcon *cont = new TrayIcon(this); + connect(cont, SIGNAL(BadIcon()), this, SLOT(checkAll()) ); + //LSession::processEvents(); + trayIcons << cont; + LI->addWidget(cont); + //qDebug() << " - Update tray layout"; + if(this->layout()->direction()==QBoxLayout::LeftToRight){ + cont->setSizeSquare(this->height()-2-2*frame->frameWidth()); //horizontal tray + this->setMaximumSize( trayIcons.length()*this->height(), 10000); + }else{ + cont->setSizeSquare(this->width()-2-2*frame->frameWidth()); //vertical tray + this->setMaximumSize(10000, trayIcons.length()*this->width()); + } + //LSession::processEvents(); + //qDebug() << " - Attach tray app"; + cont->attachApp(wins[i]); + if(cont->appID()==0){ + //could not attach window - remove the widget + qDebug() << " - Invalid Tray App: Could Not Embed:"; + trayIcons.takeAt(trayIcons.length()-1); //Always at the end + LI->removeWidget(cont); + cont->deleteLater(); + continue; + } + LI->update(); //make sure there is no blank space in the layout + } + /*if(listChanged){ + //Icons got moved around: be sure to re-draw all of them to fix visuals + for(int i=0; i<trayIcons.length(); i++){ + trayIcons[i]->update(); + } + }*/ + //qDebug() << " - System Tray: check done"; + checking = false; + if(pending){ QTimer::singleShot(0,this, SLOT(checkAll()) ); } +} + +void LSysTray::UpdateTrayWindow(WId win){ + if(!isRunning || stopping || checking){ return; } + for(int i=0; i<trayIcons.length(); i++){ + if(trayIcons[i]->appID()==win){ + //qDebug() << "System Tray: Update Window " << win; + trayIcons[i]->repaint(); //don't use update() because we need an instant repaint (not a cached version) + return; //finished now + } + } + //Could not find tray in the list, run the checkall routine to make sure we are not missing any + //qDebug() << "System Tray: Missing Window - check all"; + QTimer::singleShot(0,this, SLOT(checkAll()) ); +} + + diff --git a/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.h b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.h new file mode 100644 index 00000000..84cde5c9 --- /dev/null +++ b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.h @@ -0,0 +1,73 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2012-2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef _LUMINA_DESKTOP_SYSTRAY_H +#define _LUMINA_DESKTOP_SYSTRAY_H + +//Qt includes +#include <QFrame> +#include <QHBoxLayout> +#include <QDebug> +#include <QX11Info> +#include <QCoreApplication> + +//Local includes +#include "../LPPlugin.h" +#include "TrayIcon.h" + +//SYSTEM TRAY STANDARD DEFINITIONS +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + +class LSysTray : public LPPlugin{ + Q_OBJECT +public: + LSysTray(QWidget *parent = 0, QString id="systemtray", bool horizontal=true); + ~LSysTray(); + + virtual void AboutToClose(){ + this->stop(); + } + +private: + bool isRunning, stopping, checking, pending; + QList<TrayIcon*> trayIcons; + QFrame *frame; + QBoxLayout *LI; //layout items + QTimer *upTimer; //manual timer to force refresh of all items + +private slots: + void checkAll(); + void UpdateTrayWindow(WId win); + + //void removeTrayIcon(WId win); + +public slots: + void start(); + void stop(); + + virtual void OrientationChange(){ + //make sure the internal layout has the same orientation as the main widget + LI->setDirection( this->layout()->direction() ); + //Re-adjust the maximum widget size + int sz; + if(this->layout()->direction()==QBoxLayout::LeftToRight){ + this->setMaximumSize( trayIcons.length()*this->height(), 10000); + sz = this->height()-2*frame->frameWidth(); + }else{ + this->setMaximumSize(10000, trayIcons.length()*this->width()); + sz = this->width()-2*frame->frameWidth(); + } + for(int i=0; i<trayIcons.length(); i++){ + trayIcons[i]->setSizeSquare(sz); + trayIcons[i]->repaint(); + } + } + +}; + +#endif diff --git a/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp new file mode 100644 index 00000000..9fdbce50 --- /dev/null +++ b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp @@ -0,0 +1,128 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2014-2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "TrayIcon.h" + +#include <LSession.h> +#include <QScreen> +#include <LuminaX11.h> + +TrayIcon::TrayIcon(QWidget *parent) : QWidget(parent){ + AID = 0; //nothing yet + IID = 0; + dmgID = 0; + badpaints = 0; + //this->setLayout(new QHBoxLayout); + //this->layout()->setContentsMargins(0,0,0,0); +} + +TrayIcon::~TrayIcon(){ +} + +void TrayIcon::cleanup(){ + AID = IID = 0; +} + +WId TrayIcon::appID(){ + return AID; +} + +void TrayIcon::attachApp(WId id){ + if(id==0){ return; } //nothing to attach + else if(AID!=0){ qWarning() << "Tray Icon is already attached to a window!"; return; } + AID = id; + //WIN = QWindow::fromWinId(AID); + //connect(WIN, SIGNAL( + //this->layout()->addWidget( QWidget::createWindowContainer(WIN, this) ); + IID = this->winId(); //embed directly into this widget + dmgID = LSession::handle()->XCB->EmbedWindow(AID, IID); + if( dmgID != 0 ){ + LSession::handle()->XCB->RestoreWindow(AID); //make it visible + //qDebug() << "New System Tray App:" << AID; + QTimer::singleShot(1000, this, SLOT(updateIcon()) ); + }else{ + //qWarning() << "Could not Embed Tray Application:" << AID; + IID = 0; + AID = 0; + } +} + +void TrayIcon::setSizeSquare(int side){ + //qDebug() << " Set Fixed Systray size:" << side; + this->setFixedSize( QSize(side, side) ); +} + +// ============== +// PUBLIC SLOTS +// ============== +void TrayIcon::detachApp(){ + if(AID==0){ return; } //already detached + //qDebug() << "Detach App:" << AID; + //Temporarily move the AID, so that internal slots do not auto-run + WId tmp = AID; + AID = 0; + //Now detach the application window and clean up + //qDebug() << " - Unembed"; + //WIN->setParent(0); //Reset parentage back to the main stack + LSession::handle()->XCB->UnembedWindow(tmp); + //qDebug() << " - finished app:" << tmp; + IID = 0; +} + +// ============== +// PRIVATE SLOTS +// ============== +void TrayIcon::updateIcon(){ + if(AID==0){ return; } + //Make sure the icon is square + QSize icosize = this->size(); + LSession::handle()->XCB->ResizeWindow(AID, icosize.width(), icosize.height()); + QTimer::singleShot(500, this, SLOT(update()) ); //make sure to re-draw the window in a moment +} + +// ============= +// PROTECTED +// ============= +void TrayIcon::paintEvent(QPaintEvent *event){ + QWidget::paintEvent(event); //make sure the background is already painted + if(AID!=0){ + //Update the background on the tray app + //qDebug() << "Paint Tray Background"; + //LSession::handle()->XCB->SetWindowBackground(this, this->geometry(), AID); + //qDebug() << "Paint Tray:" << AID; + QPainter painter(this); + //Now paint the tray app on top of the background + //qDebug() << " - Draw tray:" << AID << IID << this->winId(); + //qDebug() << " - - " << event->rect().x() << event->rect().y() << event->rect().width() << event->rect().height(); + //qDebug() << " - Get image:" << AID; + QPixmap pix = LSession::handle()->XCB->TrayImage(AID); //= WIN->icon().pixmap(this->size()); + + //qDebug() << " - Pix size:" << pix.size().width() << pix.size().height(); + //qDebug() << " - Geom:" << this->geometry().x() << this->geometry().y() << this->geometry().width() << this->geometry().height(); + if(!pix.isNull()){ + if(this->size() != pix.size()){ QTimer::singleShot(10, this, SLOT(updateIcon())); } + painter.drawPixmap(0,0,this->width(), this->height(), pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation) ); + badpaints = 0; //good paint + }else{ + badpaints++; + if(badpaints>5){ + qWarning() << " - - No Tray Icon/Image found!" << "ID:" << AID; + AID = 0; //reset back to nothing + IID = 0; + emit BadIcon(); //removed/destroyed in some non-valid way? + } + } + //qDebug() << " - Done"; + } +} + +void TrayIcon::resizeEvent(QResizeEvent *event){ + //qDebug() << "Resize Event:" << event->size().width() << event->size().height(); + if(AID!=0){ + LSession::handle()->XCB->ResizeWindow(AID, event->size()); + QTimer::singleShot(500, this, SLOT(update()) ); //make sure to re-draw the window in a moment + } +} diff --git a/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.h b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.h new file mode 100644 index 00000000..5d072cc1 --- /dev/null +++ b/src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.h @@ -0,0 +1,55 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2014, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// Note: The basic idea behind this class that that it puts the app window +// in the same spot as the tray icon (to directly pass mouse events and such), +// while keeping the tray icon visual in sync with the app window +//=========================================== +#ifndef _LUMINA_PANEL_PLUGIN_SYSTEM_TRAY_ICON_H +#define _LUMINA_PANEL_PLUGIN_SYSTEM_TRAY_ICON_H + +//Qt includes +#include <QWidget> +#include <QTimer> +#include <QPaintEvent> +#include <QMoveEvent> +#include <QResizeEvent> +#include <QPainter> +#include <QPixmap> +#include <QImage> +//#include <QWindow> +// libLumina includes +//#include <LuminaX11.h> + +class TrayIcon : public QWidget{ + Q_OBJECT +public: + TrayIcon(QWidget* parent = 0); + ~TrayIcon(); + + void cleanup(); //about to be removed after window was detroyed + + WId appID(); //the ID for the attached application + void attachApp(WId id); + void setSizeSquare(int side); + +public slots: + void detachApp(); + void updateIcon(); + +private: + WId IID, AID; //icon ID and app ID + int badpaints; + uint dmgID; + +protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + +signals: + void BadIcon(); +}; +#endif
\ No newline at end of file |