1 //===========================================
2 //  Lumina-DE source code
3 //  Copyright (c) 2012-2015, Ken Moore
4 //  Available under the 3-clause BSD license
5 //  See the LICENSE file for full details
6 //===========================================
7 #include "LSysTray.h"
8 #include "../../LSession.h"
9 
LSysTray(QWidget * parent,QString id,bool horizontal)10 LSysTray::LSysTray(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
11   frame = new QFrame(this);
12   frame->setContentsMargins(0,0,0,0);
13   //frame->setStyleSheet("QFrame{ background: transparent; border: 1px solid transparent; border-radius: 3px; }");
14   LI = new QBoxLayout( this->layout()->direction());
15     frame->setLayout(LI);
16     LI->setAlignment(Qt::AlignCenter);
17     LI->setSpacing(0);
18     LI->setContentsMargins(0,0,0,0);
19   this->layout()->addWidget(frame);
20   this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
21   //TrayID=0;
22   upTimer = new QTimer(this);
23     upTimer->setInterval(300000); //maximum time between refreshes is 5 minutes
24     connect(upTimer, SIGNAL(timeout()), this, SLOT(checkAll()) );
25   isRunning = false; stopping = false; checking = false; pending = false;
26   QTimer::singleShot(100, this, SLOT(start()) );
27   //Also do one extra check a minute or so after startup (just in case something got missed in the initial flood of registrations)
28   QTimer::singleShot(90000,this, SLOT(checkAll()) );
29   connect(LSession::handle(), SIGNAL(TrayListChanged()), this, SLOT(checkAll()) );
30   connect(LSession::handle(), SIGNAL(TrayIconChanged(WId)), this, SLOT(UpdateTrayWindow(WId)) );
31   connect(LSession::handle(), SIGNAL(VisualTrayAvailable()), this, SLOT(start()) );
32 }
33 
~LSysTray()34 LSysTray::~LSysTray(){
35  if(isRunning){
36    this->stop();
37  }
38 }
39 
start()40 void LSysTray::start(){
41   if(isRunning || stopping){ return; } //already running
42   isRunning = LSession::handle()->registerVisualTray(this->winId());
43   qDebug() << "Visual Tray Started:" << this->type() << isRunning;
44   if(isRunning){
45     //upTimer->start();
46     QTimer::singleShot(0,this, SLOT(checkAll()) );
47   }
48 }
49 
stop()50 void LSysTray::stop(){
51   if(!isRunning){ return; }
52   stopping = true;
53   upTimer->stop();
54   //Now close down the system tray registry
55   qDebug() << "Stop visual system tray:" << this->type();
56   //LX11::closeSystemTray(TrayID);
57   //TrayID = 0;
58   disconnect(this); //remove any signals/slots
59   isRunning = false;
60   //Release all the tray applications and delete the containers
61   if( !LSession::handle()->currentTrayApps(this->winId()).isEmpty() ){
62     qDebug() << " - Remove tray applications";
63     //This overall system tray is not closed down - go ahead and release them here
64     for(int i=(trayIcons.length()-1); i>=0; i--){
65       trayIcons[i]->detachApp();
66       TrayIcon *cont = trayIcons.takeAt(i);
67         LI->removeWidget(cont);
68         cont->deleteLater();
69     }
70   }
71   //Now let some other visual tray take over
72   LSession::handle()->unregisterVisualTray(this->winId());
73   qDebug() << "Done stopping visual tray";
74 }
75 
76 // ========================
77 //    PRIVATE FUNCTIONS
78 // ========================
checkAll()79 void LSysTray::checkAll(){
80   if(!isRunning || stopping || checking){ pending = true; return; } //Don't check if not running at the moment
81   checking = true;
82   pending = false;
83   bool listChanged = false;
84   //Make sure this tray should handle the windows (was not disabled in the backend)
85   bool TrayRunning = LSession::handle()->registerVisualTray(this->winId());
86   //qDebug() << "System Tray: Check tray apps";
87   QList<WId> wins = LSession::handle()->currentTrayApps(this->winId());
88   for(int i=0; i<trayIcons.length(); i++){
89     int index = wins.indexOf(trayIcons[i]->appID());
90     if(index < 0){
91       //Tray Icon no longer exists: remove it
92       qDebug() << " - Visual System Tray: Remove Icon:" << trayIcons[i]->appID();
93       TrayIcon *cont = trayIcons.takeAt(i);
94       cont->cleanup();
95       LI->removeWidget(cont);
96       cont->deleteLater();
97       i--; //List size changed
98       listChanged = true;
99       //Re-adjust the maximum widget size to account for what is left
100       if(this->layout()->direction()==QBoxLayout::LeftToRight){
101         this->setMaximumSize( trayIcons.length()*this->height(), 10000);
102       }else{
103         this->setMaximumSize(10000, trayIcons.length()*this->width());
104       }
105     }else{
106       //Tray Icon already exists
107       //qDebug() << " - SysTray: Update Icon";
108       //trayIcons[i]->repaint();
109       wins.removeAt(index); //Already found - remove from the list
110     }
111   }
112   //Now go through any remaining windows and add them
113   for(int i=0; i<wins.length() && TrayRunning; i++){
114     qDebug() << " - Visual System Tray: Add Icon:" << wins[i];
115     TrayIcon *cont = new TrayIcon(this);
116       connect(cont, SIGNAL(BadIcon()), this, SLOT(checkAll()) );
117       //LSession::processEvents();
118       trayIcons << cont;
119       LI->addWidget(cont);
120       //qDebug() << " - Update tray layout";
121       if(this->layout()->direction()==QBoxLayout::LeftToRight){
122         int sz = this->height()-2-2*frame->frameWidth();
123         if(sz>64){ sz = 64; }
124         cont->setSizeSquare(sz); //horizontal tray
125 	this->setMaximumSize( trayIcons.length()*this->height(), 10000);
126       }else{
127         int sz = this->width()-2-2*frame->frameWidth();
128         if(sz>64){ sz = 64; }
129 	cont->setSizeSquare(sz); //vertical tray
130 	this->setMaximumSize(10000, trayIcons.length()*this->width());
131       }
132       //LSession::processEvents();
133       //qDebug() << " - Attach tray app";
134       cont->attachApp(wins[i]);
135       if(cont->appID()==0){
136 	//could not attach window - remove the widget
137 	qDebug() << " - Invalid Tray App: Could Not Embed:";
138 	trayIcons.takeAt(trayIcons.length()-1); //Always at the end
139 	LI->removeWidget(cont);
140 	cont->deleteLater();
141 	continue;
142       }
143     LI->update(); //make sure there is no blank space in the layout
144     listChanged = true;
145   }
146   if(listChanged){
147     //Icons got moved around: be sure to re-draw all of them to fix visuals
148     for(int i=0; i<trayIcons.length(); i++){
149       trayIcons[i]->repaint();
150     }
151   }
152   //qDebug() << " - System Tray: check done";
153   checking = false;
154   if(pending){ QTimer::singleShot(0,this, SLOT(checkAll()) ); }
155 }
156 
UpdateTrayWindow(WId win)157 void LSysTray::UpdateTrayWindow(WId win){
158   if(!isRunning || stopping || checking){ return; }
159   for(int i=0; i<trayIcons.length(); i++){
160     if(trayIcons[i]->appID()==win){
161       //qDebug() << "System Tray: Update Window " << win;
162       trayIcons[i]->repaint(); //don't use update() because we need an instant repaint (not a cached version)
163       return; //finished now
164     }
165   }
166   //Could not find tray in the list, run the checkall routine to make sure we are not missing any
167   //qDebug() << "System Tray: Missing Window - check all";
168   QTimer::singleShot(0,this, SLOT(checkAll()) );
169 }
170