aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-desktop/panel-plugins/systemtray
diff options
context:
space:
mode:
authorKen Moore <moorekou@gmail.com>2016-04-25 13:08:12 -0400
committerKen Moore <moorekou@gmail.com>2016-04-25 13:08:12 -0400
commited5ecf7ea7a482b4649e66ecb35fbc60af680684 (patch)
treeacc0fa17d228259e847f55c678db9fb0a9b50f0c /src-qt5/core/lumina-desktop/panel-plugins/systemtray
parentMerge branch 'master' of github.com:pcbsd/lumina (diff)
downloadlumina-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')
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp164
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/systemtray/LSysTray.h73
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp128
-rw-r--r--src-qt5/core/lumina-desktop/panel-plugins/systemtray/TrayIcon.h55
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
bgstack15