aboutsummaryrefslogtreecommitdiff
path: root/lumina-desktop/panel-plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lumina-desktop/panel-plugins')
-rw-r--r--lumina-desktop/panel-plugins/LPPlugin.h65
-rw-r--r--lumina-desktop/panel-plugins/LTBWidget.h67
-rw-r--r--lumina-desktop/panel-plugins/NewPP.h56
-rw-r--r--lumina-desktop/panel-plugins/battery/LBattery.cpp106
-rw-r--r--lumina-desktop/panel-plugins/battery/LBattery.h49
-rw-r--r--lumina-desktop/panel-plugins/battery/NOTES49
-rw-r--r--lumina-desktop/panel-plugins/clock/LClock.cpp35
-rw-r--r--lumina-desktop/panel-plugins/clock/LClock.h34
-rw-r--r--lumina-desktop/panel-plugins/desktopbar/LDeskBar.cpp206
-rw-r--r--lumina-desktop/panel-plugins/desktopbar/LDeskBar.h85
-rw-r--r--lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.cpp133
-rw-r--r--lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.h67
-rw-r--r--lumina-desktop/panel-plugins/spacer/LSpacer.h34
-rw-r--r--lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.cpp88
-rw-r--r--lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.h66
-rw-r--r--lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.cpp162
-rw-r--r--lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.h52
-rw-r--r--lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.ui348
-rw-r--r--lumina-desktop/panel-plugins/systemtray/LSysTray.cpp249
-rw-r--r--lumina-desktop/panel-plugins/systemtray/LSysTray.h76
-rw-r--r--lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp142
-rw-r--r--lumina-desktop/panel-plugins/systemtray/TrayIcon.h60
-rw-r--r--lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp194
-rw-r--r--lumina-desktop/panel-plugins/taskmanager/LTaskButton.h64
-rw-r--r--lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp101
-rw-r--r--lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h68
-rw-r--r--lumina-desktop/panel-plugins/taskmanager/LWinInfo.h84
-rw-r--r--lumina-desktop/panel-plugins/userbutton/LUserButton.cpp45
-rw-r--r--lumina-desktop/panel-plugins/userbutton/LUserButton.h64
-rw-r--r--lumina-desktop/panel-plugins/userbutton/UserItemWidget.cpp111
-rw-r--r--lumina-desktop/panel-plugins/userbutton/UserItemWidget.h56
-rw-r--r--lumina-desktop/panel-plugins/userbutton/UserWidget.cpp215
-rw-r--r--lumina-desktop/panel-plugins/userbutton/UserWidget.h82
-rw-r--r--lumina-desktop/panel-plugins/userbutton/UserWidget.ui385
34 files changed, 3698 insertions, 0 deletions
diff --git a/lumina-desktop/panel-plugins/LPPlugin.h b/lumina-desktop/panel-plugins/LPPlugin.h
new file mode 100644
index 00000000..ae4e7fbc
--- /dev/null
+++ b/lumina-desktop/panel-plugins/LPPlugin.h
@@ -0,0 +1,65 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the generic container layout for all panel plugins
+// Simply subclass this when creating a new plugin to enable correct
+// visibility and usage within a panel
+//===========================================
+#ifndef _LUMINA_DESKTOP_PANEL_PLUGIN_H
+#define _LUMINA_DESKTOP_PANEL_PLUGIN_H
+
+#include <QObject>
+#include <QWidget>
+#include <QString>
+#include <QBoxLayout>
+
+class LPPlugin : public QWidget{
+ Q_OBJECT
+
+private:
+ QBoxLayout *LY;
+ QString plugintype;
+
+public:
+ LPPlugin(QWidget *parent = 0, QString ptype="unknown", bool horizontal = true) : QWidget(parent){
+ plugintype=ptype;
+ this->setContentsMargins(0,0,0,0);
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ if(horizontal){LY = new QBoxLayout(QBoxLayout::LeftToRight, this); }
+ else{ LY = new QBoxLayout(QBoxLayout::TopToBottom, this); }
+ LY->setContentsMargins(0,0,0,0);
+ LY->setSpacing(1);
+ this->setLayout(LY);
+ }
+
+ ~LPPlugin(){
+ }
+
+ QBoxLayout* layout(){
+ return LY;
+ }
+
+ QString type(){
+ return plugintype;
+ }
+
+public slots:
+ virtual void LocaleChange(){
+ //This needs to be re-implemented in the subclassed plugin
+ //This is where all text is set/translated
+ }
+ virtual void ThemeChange(){
+ //This needs to be re-implemented in the subclasses plugin
+ //This is where all the visuals are set if using Theme-dependant icons.
+ }
+ virtual void OrientationChange(){
+ //This needs to be re-implemented in the subclasses plugin
+ //This is where any horizontal/vertical orientations can be changed appropriately
+ }
+
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/LTBWidget.h b/lumina-desktop/panel-plugins/LTBWidget.h
new file mode 100644
index 00000000..02097039
--- /dev/null
+++ b/lumina-desktop/panel-plugins/LTBWidget.h
@@ -0,0 +1,67 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2013, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_TOOLBAR_WIDGET_H
+#define _LUMINA_TOOLBAR_WIDGET_H
+
+#include <QToolButton>
+#include <QEvent>
+#include <QWheelEvent>
+
+#include "Globals.h"
+
+class LTBWidget : public QToolButton{
+ Q_OBJECT
+private:
+ Lumina::STATES cstate;
+ QString rawstyle;
+ void updateBackground(){
+ QString background = "background: transparent; "; //default value
+ QString border = "border: 1px solid transparent;";
+ if(cstate == Lumina::NONE){ } //just use the defaults
+ else if(cstate == Lumina::VISIBLE){ background = "background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(255, 255, 255, 240), stop:0.505682 rgba(240, 240, 240, 150), stop:1 rgba(210, 210, 210, 55));"; border="border: 1px solid transparent;"; }
+ else if(cstate == Lumina::INVISIBLE){background = "background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(215, 215, 215, 240), stop:0.505682 rgba(184, 185, 186, 150), stop:1 rgba(221, 246, 255, 55));"; border="border: 1px solid transparent;"; }
+ else if(cstate == Lumina::ACTIVE){ background= "background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(241, 233, 156, 240), stop:0.355682 rgba(255, 243, 127, 150), stop:1 rgba(221, 246, 255, 55));"; border ="border: 1px solid transparent;"; }
+ else if(cstate == Lumina::NOTIFICATION){ background= "background: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(252, 187, 127, 240), stop:0.505682 rgba(255, 222, 197, 150), stop:1 rgba(221, 246, 255, 55));"; border="border: 1px solid transparent"; }
+ QString raw = rawstyle;
+ this->setStyleSheet( raw.replace("%1",background).replace("%2", border) );
+ }
+
+signals:
+
+ void wheelScroll(int change);
+
+public:
+ LTBWidget(QWidget* parent) : QToolButton(parent){
+ //this->setStyleSheet( this->styleSheet()+" LTBWidget::menu-indicator{image: none;}");
+ cstate = Lumina::NONE;
+
+ this->setPopupMode(QToolButton::InstantPopup);
+ this->setAutoRaise(true);
+ rawstyle = "LTBWidget{ %1 %2 border-radius: 5px;} LTBWidget::menu-indicator{image: none;} LTBWidget::hover{ %1 border: 1px solid black; border-radius: 5px; } LTBWidget::menu-button{ background: transparent; width: 15px; } LTBWidget[popupMode=\"1\"]{%1 %2 border-radius: 5px; padding-right: 15px;} LTBWidget[popupMode=\"1\"]::hover{%1 border: 1px solid black; border-radius: 5px; padding-right: 15px}";
+ updateBackground();
+ }
+
+ ~LTBWidget(){
+ }
+
+ void setState(Lumina::STATES newstate){
+ cstate = newstate;
+ updateBackground();
+ }
+
+public slots:
+
+
+protected:
+ void wheelEvent(QWheelEvent *event){
+ int change = event->delta()/120; // 1/15th of a rotation (delta/120) is usually one "click" of the wheel
+ emit wheelScroll(change);
+ }
+
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/NewPP.h b/lumina-desktop/panel-plugins/NewPP.h
new file mode 100644
index 00000000..c378f07e
--- /dev/null
+++ b/lumina-desktop/panel-plugins/NewPP.h
@@ -0,0 +1,56 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is the interface to load all the different panel plugins
+//===========================================
+#ifndef _LUMINA_DESKTOP_NEW_PANEL_PLUGIN_H
+#define _LUMINA_DESKTOP_NEW_PANEL_PLUGIN_H
+
+#include <QDebug>
+
+//List all the individual plugin includes here
+#include "LPPlugin.h"
+#include "userbutton/LUserButton.h"
+#include "desktopbar/LDeskBar.h"
+#include "spacer/LSpacer.h"
+#include "clock/LClock.h"
+#include "battery/LBattery.h"
+#include "desktopswitcher/LDesktopSwitcher.h"
+#include "taskmanager/LTaskManagerPlugin.h"
+#include "systemdashboard/LSysDashboard.h"
+#include "systemtray/LSysTray.h" //must be last due to X11 compile issues
+
+class NewPP{
+public:
+ static LPPlugin* createPlugin(QString plugin, QWidget* parent = 0, bool horizontal = true){
+ LPPlugin *plug = 0;
+ if(plugin.startsWith("userbutton---")){
+ plug = new LUserButtonPlugin(parent, plugin, horizontal);
+ }else if(plugin.startsWith("desktopbar---")){
+ plug = new LDeskBarPlugin(parent, plugin, horizontal);
+ }else if(plugin.startsWith("spacer---")){
+ plug = new LSpacerPlugin(parent, plugin, horizontal);
+ }else if(plugin.startsWith("taskmanager---")){
+ plug = new LTaskManagerPlugin(parent, plugin, horizontal);
+ }else if(plugin.startsWith("systemtray---")){
+ plug = new LSysTray(parent, plugin, horizontal);
+ }else if(plugin.startsWith("desktopswitcher---")){
+ plug = new LDesktopSwitcher(parent, plugin, horizontal);
+ }else if(plugin.startsWith("battery---")){
+ plug = new LBattery(parent, plugin, horizontal);
+ }else if(plugin.startsWith("clock---")){
+ plug = new LClock(parent, plugin, horizontal);
+ }else if(plugin.startsWith("systemdashboard---")){
+ plug = new LSysDashboard(parent, plugin, horizontal);
+ }else{
+ qWarning() << "Invalid Panel Plugin:"<<plugin << " -- Ignored";
+ }
+ return plug;
+ }
+
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/battery/LBattery.cpp b/lumina-desktop/panel-plugins/battery/LBattery.cpp
new file mode 100644
index 00000000..b80a4d05
--- /dev/null
+++ b/lumina-desktop/panel-plugins/battery/LBattery.cpp
@@ -0,0 +1,106 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Susanne Jaeckel
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LBattery.h"
+
+LBattery::LBattery(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ iconOld = -1;
+ //Setup the widget
+ label = new QLabel(this);
+ label->setScaledContents(true);
+ //label->setAlignment(Qt::AlignCenter);
+ this->layout()->addWidget(label);
+ //Setup the timer
+ timer = new QTimer();
+ timer->setInterval(5000); //update every 5 seconds
+ connect(timer,SIGNAL(timeout()), this, SLOT(updateBattery()) );
+ timer->start();
+ QTimer::singleShot(0,this,SLOT(OrientationChange()) ); //update the sizing/icon
+}
+
+LBattery::~LBattery(){
+ timer->stop();
+ delete timer;
+}
+
+void LBattery::updateBattery(bool force){
+ // Get current state of charge
+ //QStringList result = LUtils::getCmdOutput("/usr/sbin/apm", QStringList() << "-al");
+ int charge = LOS::batteryCharge(); //result.at(1).toInt();
+//qDebug() << "1: " << result.at(0).toInt() << " 2: " << result.at(1).toInt();
+ int icon = -1;
+ if (charge > 90) { icon = 4; }
+ else if (charge > 70) { icon = 3; }
+ else if (charge > 50) { icon = 2; }
+ else if (charge > 30) { icon = 1; }
+ else if (charge > 0 ) { icon = 0; }
+ if(LOS::batteryIsCharging()){ icon = icon+10; }
+ //icon = icon + result.at(0).toInt() * 10;
+ if (icon != iconOld || force) {
+ switch (icon) {
+ case 0:
+ label->setPixmap( LXDG::findIcon("battery-caution", "").pixmap(label->size()) );
+ break;
+ case 1:
+ label->setPixmap( LXDG::findIcon("battery-040", "").pixmap(label->size()) );
+ break;
+ case 2:
+ label->setPixmap( LXDG::findIcon("battery-060", "").pixmap(label->size()) );
+ break;
+ case 3:
+ label->setPixmap( LXDG::findIcon("battery-080", "").pixmap(label->size()) );
+ break;
+ case 4:
+ label->setPixmap( LXDG::findIcon("battery-100", "").pixmap(label->size()) );
+ break;
+ case 10:
+ label->setPixmap( LXDG::findIcon("battery-charging-caution", "").pixmap(label->size()) );
+ break;
+ case 11:
+ label->setPixmap( LXDG::findIcon("battery-charging-040", "").pixmap(label->size()) );
+ break;
+ case 12:
+ label->setPixmap( LXDG::findIcon("battery-charging-060", "").pixmap(label->size()) );
+ break;
+ case 13:
+ label->setPixmap( LXDG::findIcon("battery-charging-080", "").pixmap(label->size()) );
+ break;
+ case 14:
+ label->setPixmap( LXDG::findIcon("battery-charging", "").pixmap(label->size()) );
+ break;
+ default:
+ label->setPixmap( LXDG::findIcon("battery-missing", "").pixmap(label->size()) );
+ break;
+ }
+ iconOld = icon;
+ }
+ //Now update the display
+ QString tt;
+ //Make sure the tooltip can be properly translated as necessary (Ken Moore 5/9/14)
+ if(icon > 9 && icon < 15){ tt = QString(tr("%1 % (Charging)")).arg(QString::number(charge)); }
+ else{ tt = QString( tr("%1 % (%2 Remaining)") ).arg(QString::number(charge), getRemainingTime() ); }
+ label->setToolTip(tt);
+}
+
+QString LBattery::getRemainingTime(){
+ int secs = LOS::batterySecondsLeft();
+ if(secs < 0){ return "??"; }
+ QString rem; //remaining
+ if(secs > 3600){
+ int hours = secs/3600;
+ rem.append( QString::number(hours)+"h ");
+ secs = secs - (hours*3600);
+ }
+ if(secs > 60){
+ int min = secs/60;
+ rem.append( QString::number(min)+"m ");
+ secs = secs - (min*60);
+ }
+ if(secs > 0){
+ rem.append(QString::number(secs)+"s");
+ }
+ return rem;
+} \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/battery/LBattery.h b/lumina-desktop/panel-plugins/battery/LBattery.h
new file mode 100644
index 00000000..a4586b37
--- /dev/null
+++ b/lumina-desktop/panel-plugins/battery/LBattery.h
@@ -0,0 +1,49 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Susanne Jaeckel
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_BATTERY_H
+#define _LUMINA_DESKTOP_BATTERY_H
+
+#include <QTimer>
+#include <QWidget>
+#include <QString>
+#include <QLabel>
+
+#include <LuminaUtils.h>
+#include <LuminaXDG.h>
+#include <LuminaOS.h>
+
+#include "../../Globals.h"
+//#include "../LTBWidget.h"
+#include "../LPPlugin.h"
+
+class LBattery : public LPPlugin{
+ Q_OBJECT
+public:
+ LBattery(QWidget *parent = 0, QString id = "battery", bool horizontal=true);
+ ~LBattery();
+
+private:
+ QTimer *timer;
+ QLabel *label;
+ int iconOld;
+
+private slots:
+ void updateBattery(bool force = false);
+ QString getRemainingTime();
+
+public slots:
+ void OrientationChange(){
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ label->setFixedSize( QSize(this->height(), this->height()) );
+ }else{
+ label->setFixedSize( QSize(this->width(), this->width()) );
+ }
+ updateBattery(true); //force icon refresh
+ }
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/battery/NOTES b/lumina-desktop/panel-plugins/battery/NOTES
new file mode 100644
index 00000000..3ea07778
--- /dev/null
+++ b/lumina-desktop/panel-plugins/battery/NOTES
@@ -0,0 +1,49 @@
+Eventuell mit einem Menü implementieren, mit Einträgen für:
+Anzeige des kompletten Status und Infos
+Herunterfahren des Systems etc.
+
+apm -a
+ Zeigt den AC line status an
+ 0 = off-line
+ 1 = on-line
+ 2 = backup-power
+
+apm -b
+ Zeigt
+ 0 = high
+ 1 = low
+ 2 = critical
+ 3 = charging
+
+apm -l
+ Zeit die prozentuale Kapazitaet
+ 255 = nicht unterstuetzt
+
+apm -t
+ Zeigt die verbleibende Zeit in Sekunden
+
+Aufruf Systemfunktionen: LuminaUtils.h
+
+mit der Methode:
+QStringList LUtils::getCmdOutput(QString cmd, QStringList args)
+
+Icons:
+/usr/local/share/icons/oxygen/22x22/status
+oder unter:
+/usr/local/share/icons/oxygen/16x16/status
+
+battery-040.png // 40 %
+battery-060.png
+battery-080.png
+battery-100.png
+
+battery-caution.png
+battery-charging.png
+battery-charging-040.png
+battery-charging-060.png
+battery-charging-080.png
+battery-charging-caution.png
+
+battery-charging-log.png
+battery-log.png
+battery-missing.png
diff --git a/lumina-desktop/panel-plugins/clock/LClock.cpp b/lumina-desktop/panel-plugins/clock/LClock.cpp
new file mode 100644
index 00000000..a61eb75d
--- /dev/null
+++ b/lumina-desktop/panel-plugins/clock/LClock.cpp
@@ -0,0 +1,35 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LClock.h"
+
+LClock::LClock(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ //Setup the widget
+ label = new QLabel(this);
+ label->setAlignment(Qt::AlignCenter);
+ this->layout()->setContentsMargins(3,0,3,0); //reserve some space on left/right
+ this->layout()->addWidget(label);
+
+ //Setup the timer
+ timer = new QTimer();
+ timer->setInterval(1000); //update once a second
+ connect(timer,SIGNAL(timeout()), this, SLOT(updateTime()) );
+ updateTime();
+ timer->start();
+}
+
+LClock::~LClock(){
+ timer->stop();
+ delete timer;
+}
+
+void LClock::updateTime(){
+ QDateTime CT = QDateTime::currentDateTime();
+ //Now update the display
+ QLocale sys = QLocale::system();
+ label->setText( "<b>"+CT.toString(sys.timeFormat(QLocale::ShortFormat))+"</b>" );
+ label->setToolTip(CT.toString(sys.dateFormat()));
+}
diff --git a/lumina-desktop/panel-plugins/clock/LClock.h b/lumina-desktop/panel-plugins/clock/LClock.h
new file mode 100644
index 00000000..d4de917c
--- /dev/null
+++ b/lumina-desktop/panel-plugins/clock/LClock.h
@@ -0,0 +1,34 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_CLOCK_H
+#define _LUMINA_DESKTOP_CLOCK_H
+
+#include <QTimer>
+#include <QDateTime>
+#include <QLabel>
+#include <QWidget>
+#include <QString>
+#include <QLocale>
+
+#include "../LPPlugin.h"
+
+class LClock : public LPPlugin{
+ Q_OBJECT
+public:
+ LClock(QWidget *parent = 0, QString id = "clock", bool horizontal=true);
+ ~LClock();
+
+private:
+ QTimer *timer;
+ QLabel *label;
+
+private slots:
+ void updateTime();
+
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/desktopbar/LDeskBar.cpp b/lumina-desktop/panel-plugins/desktopbar/LDeskBar.cpp
new file mode 100644
index 00000000..c685fbc2
--- /dev/null
+++ b/lumina-desktop/panel-plugins/desktopbar/LDeskBar.cpp
@@ -0,0 +1,206 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LDeskBar.h"
+#include "../../LSession.h"
+
+LDeskBarPlugin::LDeskBarPlugin(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ this->layout()->setContentsMargins(0,0,0,0);
+ this->setStyleSheet( "QToolButton::menu-indicator{ image: none; } QToolButton{ padding: 0px; }");
+ //Find the path to the desktop folder
+ if(QFile::exists(QDir::homePath()+"/Desktop")){ desktopPath = QDir::homePath()+"/Desktop"; }
+ else if(QFile::exists(QDir::homePath()+"/desktop")){ desktopPath = QDir::homePath()+"/desktop"; }
+ else{ desktopPath=""; }
+ //Setup the filter lists for the different types of files
+ audioFilter <<"*.ogg"<<"*.mp3"<<"*.wav"<<"*.aif"<<"*.iff"<<"*.m3u"<<"*.m4a"<<"*.mid"<<"*.mpa"<<"*.ra"<<"*.wma";
+ videoFilter <<"*.3g2"<<"*.3gp"<<"*.asf"<<"*.asx"<<"*.avi"<<"*.flv"<<"*.m4v"<<"*.mov"<<"*.mp4"<<"*.mpg"<<"*.rm"<<"*.srt"<<"*.swf"<<"*.vob"<<"*.wmv";
+ pictureFilter <<"*.bmp"<<"*.dds"<<"*.gif"<<"*.jpg"<<"*.png"<<"*.psd"<<"*.thm"<<"*.tif"<<"*.tiff"<<"*.ai"<<"*.eps"<<"*.ps"<<"*.svg"<<"*.ico";
+ docsFilter << "*.txt"<<"*.rtf"<<"*.doc"<<"*.docx"<<"*.odf"<<"*.pdf";
+ //initialize the desktop bar items
+ initializeDesktop();
+ //setup the directory watcher
+ watcher = new QFileSystemWatcher(this);
+ if(!desktopPath.isEmpty()){
+ watcher->addPath(desktopPath);
+ }
+ connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(desktopChanged()) );
+ QTimer::singleShot(1,this, SLOT(desktopChanged()) ); //make sure to load it the first time
+ QTimer::singleShot(0,this, SLOT(OrientationChange()) ); //adjust sizes/layout
+}
+
+LDeskBarPlugin::~LDeskBarPlugin(){
+ if(!desktopPath.isEmpty()){
+ watcher->removePath(desktopPath);
+ disconnect(watcher);
+ }
+ delete watcher;
+
+}
+
+// =======================
+// PRIVATE FUNCTIONS
+// =======================
+void LDeskBarPlugin::initializeDesktop(){
+ //Applications on the desktop
+ appB = new QToolButton(this);
+ appB->setIcon( LXDG::findIcon("favorites", "") );
+ appB->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ appB->setToolTip(tr("Favorite Applications"));
+ appB->setAutoRaise(true);
+ appB->setPopupMode(QToolButton::InstantPopup);
+ appM = new QMenu(this);
+ appB->setMenu(appM);
+ this->layout()->addWidget(appB);
+ connect(appM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ //Directories on the desktop
+ dirB = new QToolButton(this);
+ dirB->setIcon( LXDG::findIcon("folder", "") );
+ dirB->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ dirB->setToolTip(tr("Favorite Folders"));
+ dirB->setAutoRaise(true);
+ dirB->setPopupMode(QToolButton::InstantPopup);
+ dirM = new QMenu(this);
+ dirB->setMenu(dirM);
+ this->layout()->addWidget(dirB);
+ connect(dirM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ //Audio Files on the desktop
+ audioM = new QMenu(tr("Audio"), this);
+ connect(audioM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ audioM->setIcon( LXDG::findIcon("audio-x-generic","") );
+ //Video Files on the desktop
+ videoM = new QMenu(tr("Video"), this);
+ connect(videoM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ videoM->setIcon( LXDG::findIcon("video-x-generic","") );
+ //Picture Files on the desktop
+ pictureM = new QMenu(tr("Pictures"), this);
+ connect(pictureM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ pictureM->setIcon( LXDG::findIcon("image-x-generic","") );
+ //Other Files on the desktop
+ otherM = new QMenu(tr("Other Files"), this);
+ connect(otherM,SIGNAL(triggered(QAction*)),this,SLOT(ActionTriggered(QAction*)) );
+ otherM->setIcon( LXDG::findIcon("unknown","") );
+ docM = new QMenu(tr("Documents"), this);
+ connect(docM,SIGNAL(triggered(QAction*)), this,SLOT(ActionTriggered(QAction*)) );
+ docM->setIcon( LXDG::findIcon("x-office-document","") );
+ //All Files Button
+ fileB = new QToolButton(this);
+ fileB->setIcon( LXDG::findIcon("document-multiple", "") );
+ fileB->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ fileB->setToolTip(tr("Favorite Files") );
+ fileB->setAutoRaise(true);
+ fileB->setPopupMode(QToolButton::InstantPopup);
+ fileM = new QMenu(this);
+ fileB->setMenu(fileM);
+ this->layout()->addWidget(fileB);
+}
+
+QAction* LDeskBarPlugin::newAction(QString filepath, QString name, QString iconpath){
+ return newAction(filepath, name, QIcon(iconpath));
+}
+
+QAction* LDeskBarPlugin::newAction(QString filepath, QString name, QIcon icon){
+ QAction *act = new QAction(icon, name, this);
+ act->setWhatsThis(filepath);
+ return act;
+}
+
+void LDeskBarPlugin::updateMenu(QMenu* menu, QFileInfoList files, bool trim){
+ menu->clear();
+ //re-create the menu (since it is hidden from view)
+ for(int i=0; i<files.length(); i++){
+ qDebug() << "New Menu Item:" << files[i].fileName();
+ if(trim){ totals.removeAll(files[i]); }
+ menu->addAction( newAction( files[i].canonicalFilePath(), files[i].fileName(), "") );
+ }
+}
+
+// =======================
+// PRIVATE SLOTS
+// =======================
+void LDeskBarPlugin::ActionTriggered(QAction* act){
+ //Open up the file with the appropriate application
+ QString cmd = "lumina-open \""+act->whatsThis()+"\"";
+ qDebug() << "Open File:" << cmd;
+ LSession::LaunchApplication(cmd);
+}
+
+void LDeskBarPlugin::desktopChanged(){
+ if(!desktopPath.isEmpty()){
+ QDir dir(desktopPath);
+ totals = dir.entryInfoList( QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
+ //Update all the special menus (trimming the totals list as we go)
+ updateMenu(dirM, dir.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name) );
+ updateMenu(audioM, dir.entryInfoList( audioFilter, QDir::Files, QDir::Name) );
+ updateMenu(videoM, dir.entryInfoList( videoFilter, QDir::Files, QDir::Name) );
+ updateMenu(pictureM, dir.entryInfoList( pictureFilter, QDir::Files, QDir::Name) );
+ updateMenu(docM, dir.entryInfoList( docsFilter, QDir::Files, QDir::Name) );
+ //Now update the launchers
+ QFileInfoList exe = dir.entryInfoList( QStringList() << "*.desktop", QDir::Files, QDir::Name );
+ // - Get a complete list of apps (in alphabetical order)
+ QList<XDGDesktop> exeList;
+ for(int i=0; i<exe.length(); i++){
+ totals.removeAll(exe[i]); //Remove this item from the totals
+ bool ok = false;
+ XDGDesktop df = LXDG::loadDesktopFile(exe[i].canonicalFilePath(), ok);
+ if(ok){
+ if( LXDG::checkValidity(df) && !df.isHidden ){ exeList << df; }
+ }
+ }
+ exeList = LXDG::sortDesktopNames(exeList);
+ // - Now re-create the menu with the apps
+ appM->clear();
+ bool listApps = true; //turn this off for the moment (make dynamic later)
+ if(!listApps){
+ //go through the current items and remove them all
+ while( APPLIST.length() > 0){
+ delete this->layout()->takeAt(3); //always after the 3 main menu buttons
+ }
+ }
+ for(int i=0; i<exeList.length(); i++){
+ if(listApps){ appM->addAction( newAction(exeList[i].filePath, exeList[i].name, LXDG::findIcon(exeList[i].icon, ":/images/default-application.png")) ); }
+ else{
+ //Create a new LTBWidget for this app
+ QToolButton *it = new QToolButton(this);
+ it->setWhatsThis(exeList[i].filePath);
+ it->setToolTip(exeList[i].name);
+ it->setIcon( LXDG::findIcon(exeList[i].icon, "") );
+ it->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ it->setAutoRaise(true);
+ it->setPopupMode(QToolButton::InstantPopup);
+ if(it->icon().isNull()){ it->setIcon( LXDG::findIcon("application-x-executable","") ); }
+ connect(it, SIGNAL(triggered(QAction*)), this , SLOT(ActionTriggered(QAction*)) );
+ APPLIST << it;
+ this->layout()->addWidget(it);
+ }
+ }
+ //Now update the other menu with everything else that is left
+ updateMenu(otherM, totals, false);
+ //Now update the file menu as appropriate
+ fileM->clear();
+ if(!audioM->isEmpty()){ fileM->addMenu(audioM); }
+ if(!docM->isEmpty()){ fileM->addMenu(docM); }
+ if(!pictureM->isEmpty()){ fileM->addMenu(pictureM); }
+ if(!videoM->isEmpty()){ fileM->addMenu(videoM); }
+ if(!otherM->isEmpty()){ fileM->addMenu(otherM); }
+ //Check for a single submenu, and skip the main if need be
+ if(fileM->actions().length()==1){
+ if(!audioM->isEmpty()){ fileB->setMenu(audioM); }
+ else if(!pictureM->isEmpty()){ fileB->setMenu(pictureM); }
+ else if(!videoM->isEmpty()){ fileB->setMenu(videoM); }
+ else if(!docM->isEmpty()){ fileB->setMenu(docM); }
+ else if(!otherM->isEmpty()){ fileB->setMenu(otherM); }
+ }else{
+ fileB->setMenu(fileM);
+ }
+ }
+ //Setup the visibility of the buttons
+ appB->setVisible( !appM->isEmpty() );
+ dirB->setVisible( !dirM->isEmpty() );
+ fileB->setVisible( !fileM->isEmpty() );
+ //Clear the totals list (since no longer in use)
+ totals.clear();
+}
+
diff --git a/lumina-desktop/panel-plugins/desktopbar/LDeskBar.h b/lumina-desktop/panel-plugins/desktopbar/LDeskBar.h
new file mode 100644
index 00000000..1e42bd95
--- /dev/null
+++ b/lumina-desktop/panel-plugins/desktopbar/LDeskBar.h
@@ -0,0 +1,85 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This plugin displays the contents of the user's home directory
+// as organized within a couple buttons on the panel (apps, dirs, files)
+//===========================================
+#ifndef _LUMINA_DESKTOP_DESKBAR_H
+#define _LUMINA_DESKTOP_DESKBAR_H
+
+// Qt includes
+#include <QWidget>
+#include <QString>
+#include <QAction>
+#include <QMenu>
+#include <QProcess>
+#include <QTimer>
+#include <QFileSystemWatcher>
+#include <QHBoxLayout>
+#include <QIcon>
+#include <QToolButton>
+#include <QDebug>
+
+// libLumina includes
+#include <LuminaXDG.h>
+
+// local includes
+//#include "../LTBWidget.h"
+#include "../LPPlugin.h"
+
+class LDeskBarPlugin : public LPPlugin{
+ Q_OBJECT
+public:
+ LDeskBarPlugin(QWidget* parent=0, QString id = "desktopbar", bool horizontal=true);
+ ~LDeskBarPlugin();
+
+private:
+ //QHBoxLayout *layout;
+ QString desktopPath;
+ QFileSystemWatcher *watcher;
+ //Special toolbuttons and menus
+ QToolButton *appB, *fileB, *dirB;
+ QMenu *appM, *dirM, *audioM, *videoM, *pictureM, *fileM, *otherM, *docM;
+ QStringList audioFilter, videoFilter, pictureFilter, docsFilter;
+ QFileInfoList totals;
+ QList<QToolButton*> APPLIST;
+
+ void initializeDesktop();
+ //bool readDesktopFile(QString path, QString &name, QString &iconpath);
+
+ QAction* newAction(QString filepath, QString name, QString iconpath);
+ QAction* newAction(QString filepath, QString name, QIcon icon);
+
+ void updateMenu(QMenu* menu, QFileInfoList files, bool trim = true);
+
+
+private slots:
+ void ActionTriggered(QAction* act);
+ void desktopChanged();
+
+public slots:
+ void OrientationChange(){
+ QSize sz;
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ sz = QSize(this->height(), this->height());
+ }else{
+ this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ sz = QSize(this->width(), this->width());
+ }
+ appB->setIconSize(sz);
+ fileB->setIconSize(sz);
+ dirB->setIconSize(sz);
+ for(int i=0; i<APPLIST.length(); i++){
+ APPLIST[i]->setIconSize(sz);
+ }
+ this->layout()->update();
+ }
+};
+
+
+#endif
+
diff --git a/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.cpp b/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.cpp
new file mode 100644
index 00000000..7ab2fda1
--- /dev/null
+++ b/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.cpp
@@ -0,0 +1,133 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Susanne Jaeckel
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LDesktopSwitcher.h"
+
+LDesktopSwitcher::LDesktopSwitcher(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal) {
+ iconOld = -1;
+ this->setStyleSheet( "QToolButton::menu-indicator{ image: none; } QToolButton{padding: 0px;}");
+ //Setup the widget
+ label = new QToolButton(this);
+ label->setPopupMode(QToolButton::InstantPopup);
+ label->setAutoRaise(true);
+ label->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ label->setIcon( LXDG::findIcon("preferences-desktop-display-color", "") );
+ label->setToolTip(QString("Workspace 1"));
+ menu = new QMenu(this);
+ connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(menuActionTriggered(QAction*)));
+ label->setMenu(menu);
+ this->layout()->addWidget(label);
+
+ // Maybe a timer should be set to set the toolTip of the button,
+ // becasue the workspace could be switched via Keyboard-shortcuts ...
+
+ QTimer::singleShot(500, this, SLOT(createMenu()) ); //needs a delay to make sure it works right the first time
+ QTimer::singleShot(0,this, SLOT(OrientationChange()) ); //adjust icon size
+}
+
+LDesktopSwitcher::~LDesktopSwitcher(){
+}
+/* MOVED THESE FUNCTIONS TO LIBLUMINA (LuminaX11.h) -- Ken Moore 5/9/14
+void LDesktopSwitcher::setNumberOfDesktops(int number) {
+ Display *display = QX11Info::display();
+ Window rootWindow = QX11Info::appRootWindow();
+
+ Atom atom = XInternAtom(display, "_NET_NUMBER_OF_DESKTOPS", False);
+ XEvent xevent;
+ xevent.type = ClientMessage;
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.display = display;
+ xevent.xclient.window = rootWindow;
+ xevent.xclient.message_type = atom;
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = number;
+ xevent.xclient.data.l[1] = CurrentTime;
+ xevent.xclient.data.l[2] = 0;
+ xevent.xclient.data.l[3] = 0;
+ xevent.xclient.data.l[4] = 0;
+ XSendEvent(display, rootWindow, False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
+
+ XFlush(display);
+}
+
+void LDesktopSwitcher::setCurrentDesktop(int number) {
+ Display *display = QX11Info::display();
+ Window rootWindow = QX11Info::appRootWindow();
+
+ Atom atom = XInternAtom(display, "_NET_CURRENT_DESKTOP", False);
+ XEvent xevent;
+ xevent.type = ClientMessage;
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.display = display;
+ xevent.xclient.window = rootWindow;
+ xevent.xclient.message_type = atom;
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = number;
+ xevent.xclient.data.l[1] = CurrentTime;
+ xevent.xclient.data.l[2] = 0;
+ xevent.xclient.data.l[3] = 0;
+ xevent.xclient.data.l[4] = 0;
+ XSendEvent(display, rootWindow, False, SubstructureNotifyMask | SubstructureRedirectMask, &xevent);
+
+ XFlush(display);
+}
+
+int LDesktopSwitcher::getNumberOfDesktops() {
+ int number = -1;
+ Atom a = XInternAtom(QX11Info::display(), "_NET_NUMBER_OF_DESKTOPS", true);
+ Atom realType;
+ int format;
+ unsigned long num, bytes;
+ unsigned char *data = 0;
+ int status = XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), a, 0L, (~0L),
+ false, AnyPropertyType, &realType, &format, &num, &bytes, &data);
+ if( (status >= Success) && (num > 0) ){
+ number = *data;
+ XFree(data);
+ }
+ return number;
+}
+
+int LDesktopSwitcher::getCurrentDesktop() {
+ int number = -1;
+ Atom a = XInternAtom(QX11Info::display(), "_NET_CURRENT_DESKTOP", true);
+ Atom realType;
+ int format;
+ unsigned long num, bytes;
+ unsigned char *data = 0;
+ int status = XGetWindowProperty(QX11Info::display(), QX11Info::appRootWindow(), a, 0L, (~0L),
+ false, AnyPropertyType, &realType, &format, &num, &bytes, &data);
+ if( (status >= Success) && (num > 0) ){
+ number = *data;
+ XFree(data);
+ }
+ return number;
+} */
+
+QAction* LDesktopSwitcher::newAction(int what, QString name) {
+ QAction *act = new QAction(LXDG::findIcon("preferences-desktop-display-color", ":/images/preferences-desktop-display-color.png"), name, this);
+ act->setWhatsThis(QString::number(what));
+ return act;
+}
+
+void LDesktopSwitcher::createMenu() {
+ int cur = LX11::GetCurrentDesktop(); //current desktop number
+ int tot = LX11::GetNumberOfDesktops(); //total number of desktops
+ //qDebug() << "-- vor getCurrentDesktop SWITCH";
+ qDebug() << "Virtual Desktops:" << tot << cur;
+ menu->clear();
+ for (int i = 0; i < tot; i++) {
+ QString name = QString(tr("Workspace %1")).arg( QString::number(i+1) );
+ if(i == cur){ name.prepend("*"); name.append("*");} //identify which desktop this is currently
+ menu->addAction(newAction(i, name));
+ }
+}
+
+void LDesktopSwitcher::menuActionTriggered(QAction* act) {
+ LX11::SetCurrentDesktop(act->whatsThis().toInt());
+ label->setToolTip(QString(tr("Workspace %1")).arg(act->whatsThis().toInt() +1));
+ QTimer::singleShot(500, this, SLOT(createMenu()) ); //make sure the menu gets updated
+}
diff --git a/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.h b/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.h
new file mode 100644
index 00000000..bd23d8e9
--- /dev/null
+++ b/lumina-desktop/panel-plugins/desktopswitcher/LDesktopSwitcher.h
@@ -0,0 +1,67 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Susanne Jaeckel
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_SWITCHER_H
+#define _LUMINA_DESKTOP_SWITCHER_H
+
+#include <QTimer>
+#include <QWidget>
+#include <QString>
+//#include <QX11Info>
+#include <QMenu>
+#include <QToolButton>
+
+#include <LuminaUtils.h>
+#include <LuminaXDG.h>
+#include <LuminaX11.h>
+
+//#include "../LTBWidget.h"
+#include "../LPPlugin.h"
+
+//#include <X11/Xlib.h>
+//#include <X11/Xutil.h>
+//#include <X11/Xatom.h>
+
+class LDesktopSwitcher : public LPPlugin{
+ Q_OBJECT
+public:
+ LDesktopSwitcher(QWidget *parent = 0, QString id = "desktopswitcher", bool horizontal=true);
+ ~LDesktopSwitcher();
+
+private:
+ QTimer *timer;
+ QToolButton *label;
+ QMenu *menu;
+ int iconOld;
+
+ //void setNumberOfDesktops(int);
+ //void setCurrentDesktop(int);
+ //int getNumberOfDesktops();
+ //int getCurrentDesktop();
+
+
+ QAction* newAction(int, QString);
+
+private slots:
+ void createMenu();
+ void menuActionTriggered(QAction*);
+
+public slots:
+ void OrientationChange(){
+ QSize sz;
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ sz = QSize(this->height(), this->height());
+ }else{
+ this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ sz = QSize(this->width(), this->width());
+ }
+ label->setIconSize(sz);
+ this->layout()->update();
+ }
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/spacer/LSpacer.h b/lumina-desktop/panel-plugins/spacer/LSpacer.h
new file mode 100644
index 00000000..1e60c519
--- /dev/null
+++ b/lumina-desktop/panel-plugins/spacer/LSpacer.h
@@ -0,0 +1,34 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class is a generic invisible spacer for the panel
+//===========================================
+#ifndef _LUMINA_DESKTOP_PANEL_PLUGIN_SPACER_H
+#define _LUMINA_DESKTOP_PANEL_PLUGIN_SPACER_H
+
+#include "../LPPlugin.h"
+
+class LSpacerPlugin : public LPPlugin{
+ Q_OBJECT
+public:
+ LSpacerPlugin(QWidget *parent=0, QString id="spacer", bool horizontal=true) : LPPlugin(parent, id, horizontal){
+ if(horizontal){ this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); }
+ else{ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); }
+ }
+ ~LSpacerPlugin(){}
+
+public slots:
+ void OrientationChange(){
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){ //horizontal
+ this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ }else{ //vertical
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+ }
+ }
+};
+
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.cpp b/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.cpp
new file mode 100644
index 00000000..4e5b3139
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.cpp
@@ -0,0 +1,88 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LSysDashboard.h"
+
+LSysDashboard::LSysDashboard(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ upTimer = new QTimer(this);
+ upTimer->setInterval(10000); //10 second update ping
+ connect(upTimer, SIGNAL(timeout()), this, SLOT(updateIcon()));
+ button = new QToolButton(this);
+ button->setAutoRaise(true);
+ button->setToolButtonStyle(Qt::ToolButtonIconOnly);
+ button->setToolTip(QString("System Dashboard"));
+ connect(button, SIGNAL(clicked()), this, SLOT(openMenu()));
+ this->layout()->setContentsMargins(0,0,0,0);
+ this->layout()->addWidget(button);
+ menu = new QMenu(this);
+ sysmenu = new LSysMenuQuick(this);
+ connect(sysmenu, SIGNAL(CloseMenu()), this, SLOT(closeMenu()) );
+ mact = new QWidgetAction(this);
+ mact->setDefaultWidget(sysmenu);
+ menu->addAction(mact);
+
+ QTimer::singleShot(0,this, SLOT(OrientationChange())); //Update icons/sizes
+}
+
+LSysDashboard::~LSysDashboard(){
+
+}
+
+// ========================
+// PRIVATE FUNCTIONS
+// ========================
+void LSysDashboard::updateIcon(bool force){
+ //For the visual, show battery state only if important
+ static bool batcharging = false;
+ QPixmap pix;
+ if(LOS::hasBattery()){
+ int bat = LOS::batteryCharge();
+ bool charging = LOS::batteryIsCharging();
+ //Set the icon as necessary
+ if(charging && !batcharging){
+ //Charging and just plugged in
+ if(bat < 15){ button->setIcon( LXDG::findIcon("battery-charging-low","") ); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(bat < 30){ button->setIcon( LXDG::findIcon("battery-charging-caution","") ); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(force || button->icon().isNull()){ resetIcon(); }
+ }else if(!charging){
+ //Not charging (critical level or just unplugged)
+ if(bat<1){ button->setIcon( LXDG::findIcon("battery-missing","") ); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(bat < 15){ button->setIcon( LXDG::findIcon("battery-low","") ); QTimer::singleShot(5000, this, SLOT(resetIcon())); }
+ else if(bat < 30){ button->setIcon( LXDG::findIcon("battery-caution","") ); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(bat < 50 && batcharging){ button->setIcon( LXDG::findIcon("battery-040","")); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(bat < 70 && batcharging){ button->setIcon( LXDG::findIcon("battery-060","")); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(bat < 90 && batcharging){ button->setIcon( LXDG::findIcon("battery-080","")); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(batcharging){ button->setIcon( LXDG::findIcon("battery-100","")); QTimer::singleShot(5000, this, SLOT(resetIcon()));}
+ else if(force || button->icon().isNull()){ resetIcon(); }
+ }else if(force || button->icon().isNull()){
+ //Otherwise just use the default icon
+ resetIcon();
+ }
+ //Save the values for comparison later
+ batcharging = charging;
+ if( !upTimer->isActive() ){ upTimer->start(); } //only use the timer if a battery is present
+
+ // No battery - just use/set the normal icon
+ }else if(force || button->icon().isNull()){
+ resetIcon();
+ if(upTimer->isActive() ){ upTimer->stop(); } //no battery available - no refresh timer needed
+ }
+
+}
+
+void LSysDashboard::resetIcon(){
+ button->setIcon( LXDG::findIcon("dashboard-show",""));
+}
+
+void LSysDashboard::openMenu(){
+ sysmenu->UpdateMenu();
+ menu->popup(this->mapToGlobal(QPoint(0,0)));
+}
+
+void LSysDashboard::closeMenu(){
+ menu->hide();
+}
+
diff --git a/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.h b/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.h
new file mode 100644
index 00000000..9f1c5d18
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemdashboard/LSysDashboard.h
@@ -0,0 +1,66 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This panel plugin allows the user to control different system settings
+// For example: screen brightness, audio volume, workspace, and battery
+//===========================================
+#ifndef _LUMINA_DESKTOP_SYSTEM_DASHBOARD_H
+#define _LUMINA_DESKTOP_SYSTEM_DASHBOARD_H
+
+//Qt includes
+
+#include <QHBoxLayout>
+#include <QDebug>
+#include <QCoreApplication>
+#include <QPainter>
+#include <QPixmap>
+#include <QWidgetAction>
+#include <QMenu>
+#include <QTimer>
+#include <QToolButton>
+
+//libLumina includes
+#include <LuminaOS.h>
+#include <LuminaXDG.h>
+
+//Local includes
+#include "../LPPlugin.h"
+#include "SysMenuQuick.h"
+
+class LSysDashboard : public LPPlugin{
+ Q_OBJECT
+public:
+ LSysDashboard(QWidget *parent = 0, QString id="systemdashboard", bool horizontal=true);
+ ~LSysDashboard();
+
+private:
+ QMenu *menu;
+ QWidgetAction *mact;
+ LSysMenuQuick *sysmenu;
+ QToolButton *button;
+ QTimer *upTimer;
+
+private slots:
+ void updateIcon(bool force = false);
+ void resetIcon();
+ void openMenu();
+ void closeMenu();
+
+public slots:
+ void OrientationChange(){
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ button->setIconSize( QSize(this->height(), this->height()) );
+ }else{
+ this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ button->setIconSize( QSize(this->width(), this->width()) );
+ }
+ updateIcon(true); //force icon refresh
+ this->layout()->update();
+ }
+};
+
+#endif
diff --git a/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.cpp b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.cpp
new file mode 100644
index 00000000..550dbeac
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.cpp
@@ -0,0 +1,162 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "SysMenuQuick.h"
+#include "ui_SysMenuQuick.h"
+
+#include "../../LSession.h"
+#include <LuminaX11.h>
+
+LSysMenuQuick::LSysMenuQuick(QWidget *parent) : QWidget(parent), ui(new Ui::LSysMenuQuick){
+ ui->setupUi(this);
+ settings = new QSettings("panel-plugins","systemdashboard");
+ //Now reset the initial saved settings (if any)
+ LOS::setScreenBrightness( settings->value("screenbrightness",100).toInt() ); //default to 100%
+ LOS::setAudioVolume( settings->value("audiovolume", 100).toInt() ); //default to 100%
+ //Now setup the connections
+ connect(ui->slider_volume, SIGNAL(valueChanged(int)), this, SLOT(volSliderChanged()) );
+ connect(ui->slider_brightness, SIGNAL(valueChanged(int)), this, SLOT(brightSliderChanged()) );
+ connect(ui->tool_wk_prev, SIGNAL(clicked()), this, SLOT(prevWorkspace()) );
+ connect(ui->tool_wk_next, SIGNAL(clicked()), this, SLOT(nextWorkspace()) );
+ connect(ui->tool_logout, SIGNAL(clicked()), this, SLOT(startLogout()) );
+ connect(ui->tool_vol_mixer, SIGNAL(clicked()), this, SLOT(startMixer()) );
+ //And setup the default icons
+ ui->label_bright_icon->setPixmap( LXDG::findIcon("preferences-system-power-management","").pixmap(ui->label_bright_icon->maximumSize()) );
+ ui->tool_wk_prev->setIcon( LXDG::findIcon("go-previous-view",""));
+ ui->tool_wk_next->setIcon( LXDG::findIcon("go-next-view","") );
+ ui->tool_logout->setIcon( LXDG::findIcon("system-log-out","") );
+}
+
+LSysMenuQuick::~LSysMenuQuick(){
+
+}
+
+void LSysMenuQuick::UpdateMenu(){
+ //Audio Volume
+ int val = LOS::audioVolume();
+ QIcon ico;
+ if(val > 66){ ico= LXDG::findIcon("audio-volume-high",""); }
+ else if(val > 33){ ico= LXDG::findIcon("audio-volume-medium",""); }
+ else if(val > 0){ ico= LXDG::findIcon("audio-volume-low",""); }
+ else{ ico= LXDG::findIcon("audio-volume-muted",""); }
+ bool hasMixer = LOS::hasMixerUtility();
+ ui->label_vol_icon->setVisible(!hasMixer);
+ ui->tool_vol_mixer->setVisible(hasMixer);
+ if(!hasMixer){ ui->label_vol_icon->setPixmap( ico.pixmap(ui->label_vol_icon->maximumSize()) ); }
+ else{ ui->tool_vol_mixer->setIcon(ico); }
+ QString txt = QString::number(val)+"%";
+ if(val<100){ txt.prepend(" "); } //make sure no widget resizing
+ ui->label_vol_text->setText(txt);
+ if(ui->slider_volume->value()!= val){ ui->slider_volume->setValue(val); }
+ //Screen Brightness
+ val = LOS::ScreenBrightness();
+ txt = QString::number(val)+"%";
+ if(val<100){ txt.prepend(" "); } //make sure no widget resizing
+ ui->label_bright_text->setText(txt);
+ if(ui->slider_brightness->value()!=val){ ui->slider_brightness->setValue(val); }
+ //Battery Status
+ if(LOS::hasBattery()){
+ ui->group_battery->setVisible(true);
+ val = LOS::batteryCharge();
+ if(LOS::batteryIsCharging()){
+ if(val < 15){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging-low","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 30){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging-caution","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 50){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging-040","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 70){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging-060","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 90){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging-080","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else{ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-charging","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ ui->label_bat_text->setText( QString("%1%\n(%2)").arg(QString::number(val), tr("charging")) );
+ }else{
+ if(val < 1){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-missing","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 15){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-low","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 30){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-caution","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 50){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-040","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 70){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-060","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else if(val < 90){ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-080","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ else{ ui->label_bat_icon->setPixmap( LXDG::findIcon("battery-100","").pixmap(ui->label_bat_icon->maximumSize()) ); }
+ ui->label_bat_text->setText( QString("%1%\n(%2)").arg(QString::number(val), getRemainingTime()) );
+ }
+ }else{
+ ui->group_battery->setVisible(false);
+ }
+ //Workspace
+ val = LX11::GetCurrentDesktop();
+ int tot = LX11::GetNumberOfDesktops();
+ ui->group_workspace->setVisible(val>=0 && tot>1);
+ ui->label_wk_text->setText( QString(tr("%1 of %2")).arg(QString::number(val+1), QString::number(tot)) );
+}
+
+void LSysMenuQuick::volSliderChanged(){
+ int val = ui->slider_volume->value();
+ LOS::setAudioVolume(val);
+ settings->setValue("audiovolume",val);
+ QString txt = QString::number(val)+"%";
+ if(val<100){ txt.prepend(" "); } //make sure no widget resizing
+ ui->label_vol_text->setText( txt );
+ if(val > 66){ ui->label_vol_icon->setPixmap( LXDG::findIcon("audio-volume-high","").pixmap(ui->label_vol_icon->maximumSize()) ); }
+ else if(val > 33){ ui->label_vol_icon->setPixmap( LXDG::findIcon("audio-volume-medium","").pixmap(ui->label_vol_icon->maximumSize()) ); }
+ else if(val > 0){ ui->label_vol_icon->setPixmap( LXDG::findIcon("audio-volume-low","").pixmap(ui->label_vol_icon->maximumSize()) ); }
+ else{ ui->label_vol_icon->setPixmap( LXDG::findIcon("audio-volume-muted","").pixmap(ui->label_vol_icon->maximumSize()) ); }
+}
+
+void LSysMenuQuick::startMixer(){
+ emit CloseMenu();
+ LOS::startMixerUtility();
+}
+
+void LSysMenuQuick::brightSliderChanged(){
+ int val = ui->slider_brightness->value();
+ LOS::setScreenBrightness(val);
+ settings->setValue("screenbrightness",val);
+ QString txt = QString::number(val)+"%";
+ if(val<100){ txt.prepend(" "); } //make sure no widget resizing
+ ui->label_bright_text->setText( txt );
+}
+
+void LSysMenuQuick::nextWorkspace(){
+ int cur = LX11::GetCurrentDesktop();
+ int tot = LX11::GetNumberOfDesktops();
+ cur++;
+ if(cur>=tot){ cur = 0; } //back to beginning
+ LX11::SetCurrentDesktop(cur);
+ui->label_wk_text->setText( QString(tr("%1 of %2")).arg(QString::number(cur+1), QString::number(tot)) );
+}
+
+void LSysMenuQuick::prevWorkspace(){
+ int cur = LX11::GetCurrentDesktop();
+ int tot = LX11::GetNumberOfDesktops();
+ cur--;
+ if(cur<0){ cur = tot-1; } //back to last
+ LX11::SetCurrentDesktop(cur);
+ ui->label_wk_text->setText( QString(tr("%1 of %2")).arg(QString::number(cur+1), QString::number(tot)) );
+}
+
+QString LSysMenuQuick::getRemainingTime(){
+ int secs = LOS::batterySecondsLeft();
+ if(secs < 0){ return "??"; }
+ QString rem; //remaining
+ if(secs > 3600){
+ int hours = secs/3600;
+ rem.append( QString::number(hours)+"h ");
+ secs = secs - (hours*3600);
+ }
+ if(secs > 60){
+ int min = secs/60;
+ rem.append( QString::number(min)+"m ");
+ secs = secs - (min*60);
+ }
+ if(secs > 0){
+ rem.append( QString::number(secs)+"s");
+ }else{
+ rem.append( "0s" );
+ }
+ return rem;
+}
+
+void LSysMenuQuick::startLogout(){
+ emit CloseMenu();
+ LSession::systemWindow();
+} \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.h b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.h
new file mode 100644
index 00000000..7b3c2d09
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.h
@@ -0,0 +1,52 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This panel plugin allows the user to control different system settings
+// For example: screen brightness, audio volume, workspace, and battery
+//===========================================
+#ifndef _LUMINA_PANEL_QUICK_SYSTEM_MENU_H
+#define _LUMINA_PANEL_QUICK_SYSTEM_MENU_H
+
+#include <QWidget>
+#include <QSettings>
+#include <QString>
+
+#include <LuminaOS.h>
+#include <LuminaXDG.h>
+
+namespace Ui{
+ class LSysMenuQuick;
+};
+
+class LSysMenuQuick : public QWidget{
+ Q_OBJECT
+public:
+ LSysMenuQuick(QWidget *parent=0);
+ ~LSysMenuQuick();
+
+ void UpdateMenu();
+
+private:
+ Ui::LSysMenuQuick *ui;
+ QSettings *settings;
+
+ QString getRemainingTime(); //battery time left
+
+private slots:
+ void volSliderChanged();
+ void brightSliderChanged();
+ void startMixer();
+ void nextWorkspace();
+ void prevWorkspace();
+ void startLogout();
+
+
+signals:
+ void CloseMenu();
+
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.ui b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.ui
new file mode 100644
index 00000000..37cac2d4
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemdashboard/SysMenuQuick.ui
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LSysMenuQuick</class>
+ <widget class="QWidget" name="LSysMenuQuick">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>169</width>
+ <height>240</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QGroupBox{
+border-radius: 5px;
+border: 1px solid grey;
+margin-top: 1ex;
+}
+QGroupBox::title{
+subcontrol-origin: margin;
+subcontrol-position: top center;
+padding: 0 3px;
+background-color: rgba(255,255,255,255);
+border-radius: 5px;
+font-weight: bold;
+}</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>1</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="group_volume">
+ <property name="title">
+ <string>System Volume</string>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_vol_icon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_vol_mixer">
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Launch Audio Mixer</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSlider" name="slider_volume">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_vol_text">
+ <property name="text">
+ <string notr="true">100%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="group_brightness">
+ <property name="title">
+ <string>Screen Brightness</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_bright_icon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSlider" name="slider_brightness">
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_bright_text">
+ <property name="text">
+ <string notr="true">100%</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="group_battery">
+ <property name="title">
+ <string>Battery Status</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_bat_icon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_bat_text">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string notr="true">100% (Plugged in)</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="group_workspace">
+ <property name="title">
+ <string>Workspace</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="spacing">
+ <number>2</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="tool_wk_prev">
+ <property name="text">
+ <string notr="true">prev</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_wk_text">
+ <property name="text">
+ <string notr="true">1 of 2</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_wk_next">
+ <property name="text">
+ <string notr="true">next</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="styleSheet">
+ <string notr="true">QGroupBox{ border: none; }</string>
+ </property>
+ <property name="title">
+ <string/>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <property name="leftMargin">
+ <number>1</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="tool_logout">
+ <property name="font">
+ <font>
+ <pointsize>9</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>Log Out</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>22</width>
+ <height>22</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp b/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp
new file mode 100644
index 00000000..27dbaee5
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemtray/LSysTray.cpp
@@ -0,0 +1,249 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LSysTray.h"
+#include "../../LSession.h"
+
+#include <LuminaX11.h>
+//X includes (these need to be last due to Qt compile issues)
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/Xrender.h>
+#include <X11/extensions/Xdamage.h>
+
+//Static variables for damage detection (tray update notifications)
+static int dmgEvent = 0;
+static int dmgError = 0;
+
+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: 5px; }");
+ LI = new QBoxLayout( this->layout()->direction());
+ frame->setLayout(LI);
+ LI->setAlignment(Qt::AlignCenter);
+ LI->setSpacing(1);
+ 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;
+ start();
+}
+
+LSysTray::~LSysTray(){
+ if(isRunning){
+ this->stop();
+ }
+}
+
+void LSysTray::start(){
+ if(TrayID!=0){ return; } //already running
+ //Make sure we catch all events right away
+ connect(LSession::instance(),SIGNAL(aboutToQuit()),this,SLOT(closeAll()) );
+ connect(LSession::instance(),SIGNAL(TrayEvent(XEvent*)), this, SLOT(checkXEvent(XEvent*)) );
+ isRunning = true;
+ TrayID = LX11::startSystemTray(0); //LSession::desktop()->screenNumber(this));
+ if(TrayID!=0){
+ XSelectInput(QX11Info::display(), TrayID, InputOutput); //make sure TrayID events get forwarded here
+ XDamageQueryExtension( QX11Info::display(), &dmgEvent, &dmgError);
+ //Now connect the session logout signal to the close function
+ qDebug() << "System Tray Started Successfully";
+ upTimer->start();
+ //QTimer::singleShot(100, this, SLOT(initialTrayIconDetect()) );
+ }else{
+ disconnect(this);
+ }
+ isRunning = (TrayID!=0);
+}
+
+void LSysTray::stop(){
+ if(!isRunning){ return; }
+ upTimer->stop();
+ //Now close down the system tray registry
+ qDebug() << "Stop system Tray";
+ LX11::closeSystemTray(TrayID);
+ TrayID = 0;
+ disconnect(this); //remove any signals/slots
+ isRunning = false;
+ //Release all the tray applications and delete the containers
+ qDebug() << " - Remove tray applications";
+ for(int i=(trayIcons.length()-1); i>=0; i--){
+ trayIcons[i]->detachApp();
+ TrayIcon *cont = trayIcons.takeAt(i);
+ LI->removeWidget(cont);
+ delete cont;
+ }
+ qDebug() << "Done stopping system tray";
+}
+
+// ========================
+// PRIVATE FUNCTIONS
+// ========================
+void LSysTray::checkXEvent(XEvent *event){
+ if(!isRunning){ return; }
+ switch(event->type){
+ // -------------------------
+ case ClientMessage:
+ //Only check if the client is the system tray, otherwise ignore
+ if(event->xany.window == TrayID){
+ //qDebug() << "SysTray: ClientMessage";
+ switch(event->xclient.data.l[1]){
+ case SYSTEM_TRAY_REQUEST_DOCK:
+ addTrayIcon(event->xclient.data.l[2]); //Window ID
+ break;
+ //case SYSTEM_TRAY_BEGIN_MESSAGE:
+ //Let the window manager handle the pop-up messages for now
+ //break;
+ //case SYSTEM_TRAY_CANCEL_MESSAGE:
+ //Let the window manager handle the pop-up messages for now
+ //break;
+ }
+ }
+ break;
+ case SelectionClear:
+ if(event->xany.window == TrayID){
+ //qDebug() << "SysTray: Selection Clear";
+ this->stop(); //de-activate this system tray (release all embeds)
+ }
+ break;
+ case DestroyNotify:
+ //qDebug() << "SysTray: DestroyNotify";
+ removeTrayIcon(event->xany.window); //Check for removing an icon
+ break;
+
+ case ConfigureNotify:
+ for(int i=0; i<trayIcons.length(); i++){
+ if(event->xany.window==trayIcons[i]->appID()){
+ //qDebug() << "SysTray: Configure Event" << trayIcons[i]->appID();
+ trayIcons[i]->update(); //trigger a repaint event
+ break;
+ }
+ }
+ default:
+ if(event->type == dmgEvent+XDamageNotify){
+ WId ID = reinterpret_cast<XDamageNotifyEvent*>(event)->drawable;
+ //qDebug() << "SysTray: Damage Event";
+ for(int i=0; i<trayIcons.length(); i++){
+ if(ID==trayIcons[i]->appID()){
+ //qDebug() << "SysTray: Damage Event" << ID;
+ trayIcons[i]->update(); //trigger a repaint event
+ break;
+ }
+ }
+ }
+
+ }//end of switch over event type
+}
+
+void LSysTray::closeAll(){
+ //Actually close all the tray apps (not just unembed)
+ //This is used when the desktop is shutting everything down
+ for(int i=0; i<trayIcons.length(); i++){
+ LX11::CloseWindow(trayIcons[i]->appID());
+ }
+
+}
+
+void LSysTray::checkAll(){
+ for(int i=0; i<trayIcons.length(); i++){
+ trayIcons[i]->update();
+ }
+}
+
+void LSysTray::initialTrayIconDetect(){
+ // WARNING: This is still experimental and should be disabled by default!!
+ QList<WId> wins = LX11::findOrphanTrayWindows();
+ for(int i=0; i<wins.length(); i++){
+ //addTrayIcon(wins[i]);
+ qDebug() << "Initial Tray Window:" << wins[i] << LX11::WindowClass(wins[i]);
+ }
+}
+
+void LSysTray::addTrayIcon(WId win){
+ if(win == 0 || !isRunning){ return; }
+ //qDebug() << "System Tray: Add Tray Icon:" << win;
+ bool exists = false;
+ for(int i=0; i<trayIcons.length(); i++){
+ if(trayIcons[i]->appID() == win){ exists=true; break; }
+ }
+ if(!exists){
+ //qDebug() << " - New Icon Window:" << win;
+ TrayIcon *cont = new TrayIcon(this);
+ QCoreApplication::processEvents();
+ connect(cont, SIGNAL(AppClosed()), this, SLOT(trayAppClosed()) );
+ connect(cont, SIGNAL(AppAttached()), this, SLOT(updateStatus()) );
+ trayIcons << cont;
+ LI->addWidget(cont);
+ //qDebug() << " - Update tray layout";
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ cont->setSizeSquare(this->height()-2*frame->frameWidth()); //horizontal tray
+ this->setMaximumSize( trayIcons.length()*this->height(), 10000);
+ }else{
+ cont->setSizeSquare(this->width()-2*frame->frameWidth()); //vertical tray
+ this->setMaximumSize(10000, trayIcons.length()*this->width());
+ }
+ LSession::processEvents();
+ //qDebug() << " - Attach tray app";
+ cont->attachApp(win);
+ LI->update(); //make sure there is no blank space
+ }
+}
+
+void LSysTray::removeTrayIcon(WId win){
+ if(win==0 || !isRunning){ return; }
+ for(int i=0; i<trayIcons.length(); i++){
+ if(trayIcons[i]->appID()==win){
+ //qDebug() << " - Remove Icon Window:" << win;
+ //Remove it from the layout and keep going
+ TrayIcon *cont = trayIcons.takeAt(i);
+ LI->removeWidget(cont);
+ delete cont;
+ i--; //make sure we don't miss an item when we continue
+ QCoreApplication::processEvents();
+ }
+ }
+ //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());
+ }
+ LI->update(); //update the layout (no gaps)
+ this->update(); //update the main widget appearance
+}
+
+void LSysTray::updateStatus(){
+ qDebug() << "System Tray: Client Attached";
+ LI->update(); //make sure there is no blank space
+ //qDebug() << " - Items:" << trayIcons.length();
+}
+
+void LSysTray::trayAppClosed(){
+ if(!isRunning){ return; }
+ for(int i=0; i<trayIcons.length(); i++){
+ if(trayIcons[i]->appID() == 0){
+ qDebug() << "System Tray: Removing icon";
+ TrayIcon *cont = trayIcons.takeAt(i);
+ LI->removeWidget(cont);
+ delete cont;
+ QCoreApplication::processEvents();
+ }
+ }
+ //Re-adjust the maximum widget size
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ this->setMaximumSize( trayIcons.length()*this->height(), 10000);
+ }else{
+ this->setMaximumSize(10000, trayIcons.length()*this->width());
+ }
+ LI->update(); //update the layout (no gaps)
+ this->update();
+}
+
diff --git a/lumina-desktop/panel-plugins/systemtray/LSysTray.h b/lumina-desktop/panel-plugins/systemtray/LSysTray.h
new file mode 100644
index 00000000..13eb0df1
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemtray/LSysTray.h
@@ -0,0 +1,76 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2012, 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 <QX11EmbedContainer>
+#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();
+
+ void start();
+ void stop();
+
+private:
+ bool isRunning;
+ QList<TrayIcon*> trayIcons;
+ QFrame *frame;
+ QBoxLayout *LI; //layout items
+ WId TrayID;
+ QTimer *upTimer; //manual timer to force refresh of all items
+
+private slots:
+ void checkXEvent(XEvent *event);
+ void closeAll();
+ void checkAll();
+
+ void initialTrayIconDetect(); //initial scan for previously running tray apps
+ void addTrayIcon(WId win);
+ void removeTrayIcon(WId win);
+
+ void updateStatus();
+ void trayAppClosed();
+
+public slots:
+ 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/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp b/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp
new file mode 100644
index 00000000..37970051
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemtray/TrayIcon.cpp
@@ -0,0 +1,142 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "TrayIcon.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xdamage.h>
+
+static Damage dmgID = 0;
+
+TrayIcon::TrayIcon(QWidget *parent) : QWidget(parent){
+ AID = 0; //nothing attached yet
+ IID = 0;
+}
+
+TrayIcon::~TrayIcon(){
+ if(AID!=0){
+ detachApp();
+ }
+}
+
+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;
+ //qDebug() << "Container:" << this->winId();
+ //qDebug() << " - Tray:" << AID;
+ QTimer::singleShot(0,this,SLOT(slotAttach()) );
+}
+
+void TrayIcon::setSizeSquare(int 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";
+ LX11::UnembedWindow(tmp);
+ if(dmgID!=0){
+ XDamageDestroy(QX11Info::display(), dmgID);
+ }
+ qDebug() << " - finished app:" << tmp;
+ //if(IID!=this->winId()){ LX11::DestroyWindow(IID); }
+ IID = 0;
+ emit AppClosed();
+}
+
+// ==============
+// PRIVATE SLOTS
+// ==============
+void TrayIcon::slotAttach(){
+ IID = this->winId(); //embed directly into this widget
+ //IID = LX11::CreateWindow( this->winId(), this->rect() ); //Create an intermediate window to be the parent
+ if( LX11::EmbedWindow(AID, IID) ){
+ LX11::RestoreWindow(AID); //make it visible
+ //XSelectInput(QX11Info::display(), AID, StructureNotifyMask);
+ dmgID = XDamageCreate( QX11Info::display(), AID, XDamageReportRawRectangles );
+ updateIcon();
+ qDebug() << "New System Tray App:" << AID;
+ emit AppAttached();
+ QTimer::singleShot(500, this, SLOT(updateIcon()) );
+ }else{
+ qWarning() << "Could not Embed Tray Application:" << AID;
+ //LX11::DestroyWindow(IID);
+ IID = 0;
+ AID = 0;
+ emit AppClosed();
+ }
+}
+
+void TrayIcon::updateIcon(){
+ if(AID==0){ return; }
+ //Make sure the icon is square
+ QSize icosize = this->size();
+ LX11::ResizeWindow(AID, icosize.width(), icosize.height());
+}
+
+// =============
+// PROTECTED
+// =============
+void TrayIcon::paintEvent(QPaintEvent *event){
+ QWidget::paintEvent(event); //make sure the background is already painted
+ if(AID!=0){
+ //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";
+ QPixmap pix = LX11::WindowImage(AID, false);
+ if(pix.isNull()){
+ //Try to grab the window directly with Qt
+ //qDebug() << " - Grab window directly";
+ pix = QPixmap::grabWindow(AID);
+ }
+ //qDebug() << " - Pix size:" << pix.size().width() << pix.size().height();
+ //qDebug() << " - Geom:" << this->geometry().x() << this->geometry().y() << this->geometry().width() << this->geometry().height();
+ painter.drawPixmap(0,0,this->width(), this->height(), pix.scaled(this->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation) );
+ //qDebug() << " - Done";
+ }
+}
+
+/*void TrayIcon::moveEvent(QMoveEvent *event){
+ //Make sure the main Tray window is right underneath the widget
+ //qDebug() << "Move Event:" << event->pos().x() << event->pos().y();
+ LX11::MoveResizeWindow(AID, QRect( this->mapToGlobal(event->pos()), this->size()) );
+ QWidget::moveEvent(event);
+}*/
+
+void TrayIcon::resizeEvent(QResizeEvent *event){
+ //qDebug() << "Resize Event:" << event->size().width() << event->size().height();
+ if(AID!=0){
+ LX11::ResizeWindow(AID, event->size().width(), event->size().height());
+ }
+}
+
+/*bool TrayIcon::x11Event(XEvent *event){
+ qDebug() << "XEvent";
+ if( event->xany.window==AID || event->type==( (int)dmgID+XDamageNotify) ){
+ qDebug() << "Tray X Event:" << AID;
+ this->update(); //trigger a repaint
+ return true;
+ }else{
+ return false; //no special handling
+ }
+}*/
diff --git a/lumina-desktop/panel-plugins/systemtray/TrayIcon.h b/lumina-desktop/panel-plugins/systemtray/TrayIcon.h
new file mode 100644
index 00000000..97f2fdf5
--- /dev/null
+++ b/lumina-desktop/panel-plugins/systemtray/TrayIcon.h
@@ -0,0 +1,60 @@
+//===========================================
+// 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>
+
+// libLumina includes
+#include <LuminaX11.h>
+
+//Local includes
+
+class TrayIcon : public QWidget{
+ Q_OBJECT
+public:
+ TrayIcon(QWidget* parent = 0);
+ ~TrayIcon();
+
+ 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
+
+private slots:
+ void slotAttach(); //so that the attachment can be done in a new thread
+
+
+protected:
+ void paintEvent(QPaintEvent *event);
+ //void moveEvent(QMoveEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ //bool x11Event(XEvent *event);
+
+signals:
+ void AppClosed();
+ void AppAttached();
+};
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp b/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp
new file mode 100644
index 00000000..80600488
--- /dev/null
+++ b/lumina-desktop/panel-plugins/taskmanager/LTaskButton.cpp
@@ -0,0 +1,194 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LTaskButton.h"
+
+LTaskButton::LTaskButton(QWidget *parent) : LTBWidget(parent){
+ actMenu = new QMenu(this);
+ winMenu = new QMenu(this);
+ UpdateMenus();
+
+ this->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ this->setAutoRaise(false); //make sure these always look like buttons
+ this->setContextMenuPolicy(Qt::CustomContextMenu);
+ winMenu->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(openActionMenu()) );
+ connect(this, SIGNAL(clicked()), this, SLOT(buttonClicked()) );
+ connect(winMenu, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(openActionMenu()) );
+ connect(winMenu, SIGNAL(triggered(QAction*)), this, SLOT(winClicked(QAction*)) );
+}
+
+LTaskButton::~LTaskButton(){
+
+}
+
+//===========
+// PUBLIC
+//===========
+QList<LWinInfo> LTaskButton::windows(){
+ return WINLIST;
+}
+
+QString LTaskButton::classname(){
+ return cname;
+}
+
+void LTaskButton::addWindow(LWinInfo win){
+ WINLIST << win;
+ UpdateButton();
+}
+
+void LTaskButton::rmWindow(LWinInfo win){
+ for(int i=0; i<WINLIST.length(); i++){
+ if(WINLIST[i].windowID() == win.windowID()){
+ WINLIST.removeAt(i);
+ break;
+ }
+ }
+ UpdateButton();
+}
+
+//==========
+// PRIVATE
+//==========
+LWinInfo LTaskButton::currentWindow(){
+ if(WINLIST.length() == 1 || cWin.windowID()==0){
+ return WINLIST[0]; //only 1 window - this must be it
+ }else{
+ return cWin;
+ }
+}
+
+//=============
+// PUBLIC SLOTS
+//=============
+void LTaskButton::UpdateButton(){
+ if(winMenu->isVisible()){ return; } //skip this if the window menu is currently visible for now
+ bool statusOnly = WINLIST.length() == LWINLIST.length();
+ LWINLIST = WINLIST;
+
+ winMenu->clear();
+ Lumina::STATES showstate = Lumina::NOSHOW;
+ for(int i=0; i<WINLIST.length(); i++){
+ if(WINLIST[i].windowID() == 0){
+ WINLIST.removeAt(i);
+ i--;
+ continue;
+ }
+ if(i==0 && !statusOnly){
+ //Update the button visuals from the first window
+ this->setIcon(WINLIST[i].icon());
+ cname = WINLIST[i].Class();
+ if(cname.isEmpty()){
+ //Special case (chrome/chromium does not register *any* information with X except window title)
+ cname = WINLIST[i].text();
+ if(cname.contains(" - ")){ cname = cname.section(" - ",-1); }
+ }
+ this->setToolTip(cname);
+ if(this->icon().isNull()){
+ this->setIcon( LXDG::findIcon(cname.toLower(),"") );
+ if(this->icon().isNull()){
+ this->setIcon( LXDG::findIcon("preferences-system-windows","") );
+ noicon=true;
+ }else{
+ noicon = false;
+ }
+ }else{
+ noicon = false;
+ }
+ }
+ winMenu->addAction( WINLIST[i].icon(), WINLIST[i].text() );
+ Lumina::STATES stat = WINLIST[i].status();
+ if(stat==Lumina::NOTIFICATION){ showstate = stat; } //highest priority
+ else if( stat==Lumina::ACTIVE && showstate != Lumina::NOTIFICATION){ showstate = stat; } //next priority
+ else if( stat==Lumina::Lumina::VISIBLE && showstate != Lumina::NOTIFICATION && showstate != Lumina::ACTIVE){ showstate = stat; }
+ else if(showstate == Lumina::INVISIBLE || showstate == Lumina::NOSHOW){ showstate = stat; } //anything is the same/better
+ }
+ //Now setup the button appropriately
+ // - visibility
+ if(showstate == Lumina::NOSHOW || WINLIST.length() < 1){ this->setVisible(false); }
+ else{ this->setVisible(true); }
+ // - functionality
+ if(WINLIST.length() == 1){
+ //single window
+ this->setPopupMode(QToolButton::DelayedPopup);
+ this->setMenu(actMenu);
+ if(noicon){ this->setText( this->fontMetrics().elidedText(cname, Qt::ElideRight ,80) ); }
+ else{ this->setText(""); }
+ }else if(WINLIST.length() > 1){
+ //multiple windows
+ this->setPopupMode(QToolButton::InstantPopup);
+ this->setMenu(winMenu);
+ if(noicon){ this->setText( this->fontMetrics().elidedText(cname, Qt::ElideRight ,80) +" ("+QString::number(WINLIST.length())+")" ); }
+ else{ this->setText("("+QString::number(WINLIST.length())+")"); }
+ }
+ this->setState(showstate); //Make sure this is after the button setup so that it properly sets the margins/etc
+}
+
+void LTaskButton::UpdateMenus(){
+ //Action menu is very simple right now - can expand it later
+ actMenu->clear();
+ actMenu->addAction( LXDG::findIcon("window-close",""), tr("Close Window"), this, SLOT(closeWindow()) );
+}
+
+//=============
+// PRIVATE SLOTS
+//=============
+void LTaskButton::buttonClicked(){
+ if(WINLIST.length() > 1){
+ winMenu->popup(QCursor::pos());
+ }else{
+ triggerWindow();
+ }
+}
+
+void LTaskButton::closeWindow(){
+ if(winMenu->isVisible()){ winMenu->hide(); }
+ LWinInfo win = currentWindow();
+ LX11::CloseWindow(win.windowID());
+ cWin = LWinInfo(); //clear the current
+}
+
+void LTaskButton::triggerWindow(){
+ LWinInfo win = currentWindow();
+ //Check which state the window is currently in and flip it to the other
+ LX11::WINDOWSTATE state = LX11::GetWindowState(win.windowID());
+ if(state == LX11::ACTIVE){
+ qDebug() << "Minimize Window:" << this->text();
+ LX11::IconifyWindow(win.windowID());
+ }else if(state == LX11::VISIBLE){
+ qDebug() << "Activate Window:" << this->text();
+ LX11::ActivateWindow(win.windowID());
+ }else{
+ qDebug() << "Restore Window:" << this->text();
+ LX11::RestoreWindow(win.windowID());
+ }
+ cWin = LWinInfo(); //clear the current
+}
+
+void LTaskButton::winClicked(QAction* act){
+ //Get the window from the action
+ QString txt = act->text();
+ for(int i=0; i<WINLIST.length(); i++){
+ if(WINLIST[i].text() == txt){ cWin = WINLIST[i]; }
+ }
+ //Now trigger the window
+ triggerWindow();
+}
+
+void LTaskButton::openActionMenu(){
+ //Get the Window the mouse is currently over
+ QAction *act = winMenu->actionAt(QCursor::pos());
+ if( act != 0 && winMenu->isVisible() ){
+ //get the window from the action
+ QString txt = act->text();
+ for(int i=0; i<WINLIST.length(); i++){
+ if(WINLIST[i].text() == txt){ cWin = WINLIST[i]; }
+ }
+ }
+ //Now show the action menu
+ actMenu->popup(QCursor::pos());
+}
diff --git a/lumina-desktop/panel-plugins/taskmanager/LTaskButton.h b/lumina-desktop/panel-plugins/taskmanager/LTaskButton.h
new file mode 100644
index 00000000..22278eba
--- /dev/null
+++ b/lumina-desktop/panel-plugins/taskmanager/LTaskButton.h
@@ -0,0 +1,64 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_TASK_BUTTON_H
+#define _LUMINA_DESKTOP_TASK_BUTTON_H
+
+// Qt includes
+#include <QWidget>
+#include <QList>
+#include <QIcon>
+#include <QCursor>
+#include <QMenu>
+#include <QEvent>
+#include <QAction>
+
+// libLumina includes
+#include <LuminaXDG.h>
+#include <LuminaX11.h>
+
+// Local includes
+#include "LWinInfo.h"
+#include "../LTBWidget.h"
+
+class LTaskButton : public LTBWidget{
+ Q_OBJECT
+public:
+ LTaskButton(QWidget *parent=0);
+ ~LTaskButton();
+
+ //Window Information
+ QList<LWinInfo> windows();
+ QString classname();
+
+ //Window Management
+ void addWindow(LWinInfo win); //Add a window to this button
+ void rmWindow(LWinInfo win); //Remove a window from this button
+
+private:
+ QList<LWinInfo> WINLIST;
+ QList<LWinInfo> LWINLIST;
+ QMenu *actMenu; // action menu (custom context menu)
+ QMenu *winMenu; // window menu (if more than 1)
+ LWinInfo cWin;
+ QString cname; //class name for the entire button
+ bool noicon;
+
+ LWinInfo currentWindow(); //For getting the currently-active window
+
+public slots:
+ void UpdateButton(); //re-sync the current window infomation
+ void UpdateMenus(); //re-create the menus (text + icons)
+
+private slots:
+ void buttonClicked();
+ void closeWindow(); //send the signal to close a window
+ void triggerWindow(); //change b/w visible and invisible
+ void winClicked(QAction*);
+ void openActionMenu();
+
+};
+#endif
diff --git a/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp b/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp
new file mode 100644
index 00000000..674c9088
--- /dev/null
+++ b/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.cpp
@@ -0,0 +1,101 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LTaskManagerPlugin.h"
+#include "../../LSession.h"
+
+LTaskManagerPlugin::LTaskManagerPlugin(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ updating=false;
+ timer = new QTimer(this);
+ timer->setSingleShot(true);
+ timer->setInterval(10); // 1/100 second
+ connect(timer, SIGNAL(timeout()), this, SLOT(UpdateButtons()) );
+ connect(LSession::instance(), SIGNAL(WindowListEvent()), this, SLOT(checkWindows()) );
+ this->layout()->setContentsMargins(0,0,0,0);
+ QTimer::singleShot(0,this, SLOT(UpdateButtons()) ); //perform an initial sync
+ //QTimer::singleShot(100,this, SLOT(OrientationChange()) ); //perform an initial sync
+}
+
+LTaskManagerPlugin::~LTaskManagerPlugin(){
+
+}
+
+//==============
+// PRIVATE SLOTS
+//==============
+void LTaskManagerPlugin::UpdateButtons(){
+ if(updating){ timer->start(); return; } //check again in a moment
+ //Make sure this only runs one at a time
+ updating=true;
+ //Get the current window list
+ QList<WId> winlist = LX11::WindowList();
+ //qDebug() << "Update Buttons:" << winlist;
+ //Now go through all the current buttons first
+ for(int i=0; i<BUTTONS.length(); i++){
+ //Get the windows managed in this button
+ QList<LWinInfo> WI = BUTTONS[i]->windows();
+ bool updated=false;
+ for(int w=0; w<WI.length(); w++){
+ if( winlist.contains( WI[w].windowID() ) ){
+ //Still current window - update it later
+ winlist.removeAll(WI[w].windowID()); //remove this window from the list since it is done
+ }else{
+ //Window was closed - remove it
+ if(WI.length()==1){
+ //Remove the entire button
+ this->layout()->takeAt(i); //remove from the layout
+ delete BUTTONS.takeAt(i);
+ i--;
+ updated = true; //prevent updating a removed button
+ break; //break out of the button->window loop
+ }else{
+ //qDebug() << "Remove Window:" << WI[w].windowID() << "Button:" << w;
+ BUTTONS[i]->rmWindow(WI[w]); // one of the multiple windows for the button
+ WI.removeAt(w); //remove this window from the list
+ w--;
+ }
+ updated=true; //button already changed
+ }
+ }
+ if(!updated){
+ //qDebug() << "Update Button:" << i;
+ QTimer::singleShot(1,BUTTONS[i], SLOT(UpdateButton()) ); //keep moving on
+ }
+ }
+ //Now go through the remaining windows
+ for(int i=0; i<winlist.length(); i++){
+ //New windows, create buttons for each (add grouping later)
+ //Check for a button that this can just be added to
+ QString ctxt = LX11::WindowClass(winlist[i]);
+ bool found = false;
+ for(int b=0; b<BUTTONS.length(); b++){
+ if(BUTTONS[b]->classname()== ctxt){
+ found = true;
+ //qDebug() << "Add Window to Button:" << b;
+ BUTTONS[b]->addWindow(winlist[i]);
+ break;
+ }
+ }
+ if(!found){
+ //No group, create a new button
+ //qDebug() << "New Button";
+ LTaskButton *but = new LTaskButton(this);
+ but->addWindow( LWinInfo(winlist[i]) );
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ but->setIconSize(QSize(this->height(), this->height()));
+ }else{
+ but->setIconSize(QSize(this->width(), this->width()));
+ }
+ this->layout()->addWidget(but);
+ BUTTONS << but;
+ }
+ }
+ updating=false; //flag that we are done updating the buttons
+}
+
+void LTaskManagerPlugin::checkWindows(){
+ timer->start();
+} \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h b/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h
new file mode 100644
index 00000000..ca470da6
--- /dev/null
+++ b/lumina-desktop/panel-plugins/taskmanager/LTaskManagerPlugin.h
@@ -0,0 +1,68 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_TASK_MANAGER_PLUGIN_H
+#define _LUMINA_DESKTOP_TASK_MANAGER_PLUGIN_H
+
+// Qt includes
+#include <QWidget>
+#include <QList>
+#include <QString>
+#include <QDebug>
+#include <QTimer>
+#include <QEvent>
+
+// libLumina includes
+#include <LuminaX11.h>
+
+// Local includes
+#include "LTaskButton.h"
+#include "LWinInfo.h"
+#include "../LPPlugin.h"
+
+class LTaskManagerPlugin : public LPPlugin{
+ Q_OBJECT
+public:
+ LTaskManagerPlugin(QWidget *parent=0, QString id="taskmanager", bool horizontal=true);
+ ~LTaskManagerPlugin();
+
+private:
+ QList<LTaskButton*> BUTTONS; //to keep track of the current buttons
+ QTimer *timer;
+ bool updating; //quick flag for if it is currently working
+
+private slots:
+ void UpdateButtons();
+ void checkWindows();
+
+public slots:
+ void LocaleChange(){
+ UpdateButtons();
+ }
+ void ThemeChange(){
+ UpdateButtons();
+ }
+ void OrientationChange(){
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){ //horizontal
+ this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ this->layout()->setAlignment(Qt::AlignLeft);
+ QSize sz(this->height(), this->height());
+ for(int i=0; i<BUTTONS.length(); i++){
+ BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ BUTTONS[i]->setIconSize(sz);
+ }
+ }else{ //vertical
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+ this->layout()->setAlignment(Qt::AlignTop);
+ QSize sz(this->width(), this->width());
+ for(int i=0; i<BUTTONS.length(); i++){
+ BUTTONS[i]->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ BUTTONS[i]->setIconSize(sz);
+ }
+ }
+ }
+};
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/taskmanager/LWinInfo.h b/lumina-desktop/panel-plugins/taskmanager/LWinInfo.h
new file mode 100644
index 00000000..1084e6e3
--- /dev/null
+++ b/lumina-desktop/panel-plugins/taskmanager/LWinInfo.h
@@ -0,0 +1,84 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_WINDOW_INFO_H
+#define _LUMINA_DESKTOP_WINDOW_INFO_H
+
+// Qt includes
+#include <QString>
+#include <QPixmap>
+#include <QIcon>
+#include <QPainter>
+
+// libLumina includes
+#include <LuminaX11.h>
+#include <LuminaXDG.h>
+
+// Local includes
+#include "../../Globals.h" //For the STATES enumeration definition
+
+
+class LWinInfo{
+private:
+ WId window;
+
+public:
+ LWinInfo(WId id = 0){
+ window = id;
+ }
+ ~LWinInfo(){};
+
+ //The current window ID
+ WId windowID(){
+ return window;
+ }
+
+ //Information Retrieval
+ // Don't cache these results because they can change regularly
+ QString text(){
+ if(window==0){ return ""; }
+ QString nm = LX11::WindowVisibleIconName(window);
+ if(nm.isEmpty()){ nm = LX11::WindowIconName(window); }
+ if(nm.isEmpty()){ nm = LX11::WindowVisibleName(window); }
+ if(nm.isEmpty()){ nm = LX11::WindowName(window); }
+ return nm;
+ }
+
+ QIcon icon(){
+ if(window==0){ return QIcon(); }
+ //qDebug() << "Check for Window Icon:" << window;
+ QIcon ico = LX11::WindowIcon(window);
+ //Check for a null icon, and supply one if necessary
+ //if(ico.isNull()){ ico = LXDG::findIcon("preferences-system-windows",""); }
+ return ico;
+ }
+
+ QString Class(){
+ return LX11::WindowClass(window);
+ }
+
+ Lumina::STATES status(){
+ if(window==0){ return Lumina::NOSHOW; }
+ LX11::WINDOWSTATE ws = LX11::GetWindowState(window);
+ Lumina::STATES state;
+ switch(ws){
+ case LX11::VISIBLE:
+ state = Lumina::VISIBLE; break;
+ case LX11::INVISIBLE:
+ state = Lumina::INVISIBLE; break;
+ case LX11::ACTIVE:
+ state = Lumina::ACTIVE; break;
+ case LX11::ATTENTION:
+ state = Lumina::NOTIFICATION; break;
+ default:
+ state = Lumina::NOSHOW;
+ }
+ //qDebug() << "Window State:" << ws << state;
+ return state;
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/userbutton/LUserButton.cpp b/lumina-desktop/panel-plugins/userbutton/LUserButton.cpp
new file mode 100644
index 00000000..74509920
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/LUserButton.cpp
@@ -0,0 +1,45 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LUserButton.h"
+#include "../../LSession.h"
+
+LUserButtonPlugin::LUserButtonPlugin(QWidget *parent, QString id, bool horizontal) : LPPlugin(parent, id, horizontal){
+ button = new QToolButton(this);
+ button->setAutoRaise(true);
+ button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
+ button->setToolTip(QString("Quickly launch applications or open files"));
+ button->setText( SYSTEM::user() );
+ connect(button, SIGNAL(clicked()), this, SLOT(openMenu()));
+ this->layout()->setContentsMargins(0,0,0,0);
+ this->layout()->addWidget(button);
+ menu = new QMenu(this);
+ menu->setContentsMargins(1,1,1,1);
+ usermenu = new UserWidget(this);
+ connect(usermenu, SIGNAL(CloseMenu()), this, SLOT(closeMenu()) );
+ mact = new QWidgetAction(this);
+ mact->setDefaultWidget(usermenu);
+ menu->addAction(mact);
+
+ QTimer::singleShot(0,this, SLOT(OrientationChange())); //Update icons/sizes
+}
+
+LUserButtonPlugin::~LUserButtonPlugin(){
+
+}
+
+// ========================
+// PRIVATE FUNCTIONS
+// ========================
+void LUserButtonPlugin::openMenu(){
+ usermenu->UpdateMenu();
+ menu->popup(this->mapToGlobal(QPoint(0,0)));
+}
+
+void LUserButtonPlugin::closeMenu(){
+ menu->hide();
+}
+
diff --git a/lumina-desktop/panel-plugins/userbutton/LUserButton.h b/lumina-desktop/panel-plugins/userbutton/LUserButton.h
new file mode 100644
index 00000000..e6a1830d
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/LUserButton.h
@@ -0,0 +1,64 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This panel plugin is the main button that allow the user to run
+// applications or logout of the desktop
+//===========================================
+#ifndef _LUMINA_DESKTOP_USER_MENU_PLUGIN_H
+#define _LUMINA_DESKTOP_USER_MENU_PLUGIN_H
+
+// Qt includes
+#include <QMenu>
+#include <QWidgetAction>
+#include <QToolButton>
+#include <QString>
+#include <QWidget>
+
+
+// Lumina-desktop includes
+#include "../../Globals.h"
+#include "../LPPlugin.h" //main plugin widget
+
+// libLumina includes
+#include "LuminaXDG.h"
+
+#include "UserWidget.h"
+
+// PANEL PLUGIN BUTTON
+class LUserButtonPlugin : public LPPlugin{
+ Q_OBJECT
+
+public:
+ LUserButtonPlugin(QWidget *parent = 0, QString id = "userbutton", bool horizontal=true);
+ ~LUserButtonPlugin();
+
+private:
+ QMenu *menu;
+ QWidgetAction *mact;
+ UserWidget *usermenu;
+ QToolButton *button;
+
+
+
+private slots:
+ void openMenu();
+ void closeMenu();
+
+public slots:
+ void OrientationChange(){
+ if(this->layout()->direction()==QBoxLayout::LeftToRight){
+ this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
+ button->setIconSize( QSize(this->height(), this->height()) );
+ }else{
+ this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
+ button->setIconSize( QSize(this->width(), this->width()) );
+ }
+ button->setIcon( LXDG::findIcon("user-identity", ":/images/default-user.png") ); //force icon refresh
+ this->layout()->update();
+ }
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/userbutton/UserItemWidget.cpp b/lumina-desktop/panel-plugins/userbutton/UserItemWidget.cpp
new file mode 100644
index 00000000..c279a2a4
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/UserItemWidget.cpp
@@ -0,0 +1,111 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "UserItemWidget.h"
+
+UserItemWidget::UserItemWidget(QWidget *parent, QString itemPath, bool isDir) : QFrame(parent){
+ createWidget();
+ //Now fill it appropriately
+ if(itemPath.endsWith(".desktop")){
+ bool ok = false;
+ XDGDesktop item = LXDG::loadDesktopFile(itemPath, ok);
+ if(ok){
+ icon->setPixmap( LXDG::findIcon(item.icon, "preferences-system-windows-actions").pixmap(30,30) );
+ name->setText( item.name );
+ icon->setWhatsThis(item.filePath);
+ }else{
+ icon->setPixmap( LXDG::findIcon("unknown","").pixmap(30,30) );
+ name->setText( itemPath.section("/",-1) );
+ icon->setWhatsThis(itemPath);
+ }
+ }else if(isDir){
+ if(itemPath.endsWith("/")){ itemPath.chop(1); }
+ icon->setPixmap( LXDG::findIcon("folder","").pixmap(30,30) );
+ name->setText( itemPath.section("/",-1) );
+ icon->setWhatsThis(itemPath);
+ }else{
+ if(itemPath.endsWith("/")){ itemPath.chop(1); }
+ icon->setPixmap( LXDG::findMimeIcon(itemPath.section("/",-1).section(".",-1)).pixmap(30,30) );
+ name->setText( itemPath.section("/",-1) );
+ icon->setWhatsThis(itemPath);
+ }
+ if(isDir && !QFile::symLinkTarget(itemPath).isEmpty()){ isDir = false; } //not a real directory - just a sym link
+ isDirectory = isDir; //save this for later
+ //Now setup the button appropriately
+ setupButton();
+}
+
+UserItemWidget::UserItemWidget(QWidget *parent, XDGDesktop item) : QFrame(parent){
+ createWidget();
+ isDirectory = false;
+ //Now fill it appropriately
+ icon->setPixmap( LXDG::findIcon(item.icon,"preferences-system-windows-actions").pixmap(30,30) );
+ name->setText( item.name );
+ icon->setWhatsThis(item.filePath);
+ //Now setup the button appropriately
+ setupButton();
+
+}
+
+UserItemWidget::~UserItemWidget(){
+ delete button;
+ delete icon;
+ delete name;
+}
+
+
+void UserItemWidget::createWidget(){
+ //Initialize the widgets
+ this->setContentsMargins(0,0,0,0);
+ button = new QToolButton(this);
+ button->setIconSize( QSize(14,14) );
+ button->setAutoRaise(true);
+ icon = new QLabel(this);
+ icon->setFixedSize( QSize(30,30) );
+ name = new QLabel(this);
+ //Add them to the layout
+ this->setLayout(new QHBoxLayout());
+ this->layout()->setContentsMargins(1,1,1,1);
+ this->layout()->addWidget(icon);
+ this->layout()->addWidget(name);
+ this->layout()->addWidget(button);
+ //Install the stylesheet
+ this->setStyleSheet("UserItemWidget{ background: transparent; border-radius: 5px;} UserItemWidget::hover{ background: rgba(255,255,255,200); border-radius: 5px; }");
+}
+
+void UserItemWidget::setupButton(){
+ if( !isDirectory && icon->whatsThis().contains("/home/") && icon->whatsThis().contains("/Desktop/")){
+ //This is a current desktop shortcut -- allow the user to remove it
+ button->setWhatsThis("remove");
+ button->setIcon( LXDG::findIcon("list-remove","") );
+ button->setToolTip(tr("Remove Shortcut"));
+ connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked()) );
+ }else if( !isDirectory && !QFile::exists( QDir::homePath()+"/Desktop/"+icon->whatsThis().section("/",-1) ) ){
+ //This file does not have a desktop shortcut yet -- allow the user to add it
+ button->setWhatsThis("add");
+ button->setIcon( LXDG::findIcon("favorites","") );
+ button->setToolTip(tr("Create Shortcut"));
+ connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked()) );
+ }else{
+ //This already has a desktop shortcut -- no special actions
+ button->setVisible(false);
+ }
+}
+
+void UserItemWidget::buttonClicked(){
+ button->setVisible(false);
+ if(button->whatsThis()=="add"){
+ QFile::link(icon->whatsThis(), QDir::homePath()+"/Desktop/"+icon->whatsThis().section("/",-1) );
+ emit NewShortcut();
+ }else if(button->whatsThis()=="remove"){
+ QFile::remove(icon->whatsThis());
+ emit RemovedShortcut();
+ }
+}
+
+void UserItemWidget::ItemClicked(){
+ emit RunItem("lumina-open \""+icon->whatsThis()+"\"" );
+} \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/userbutton/UserItemWidget.h b/lumina-desktop/panel-plugins/userbutton/UserItemWidget.h
new file mode 100644
index 00000000..3a4406ac
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/UserItemWidget.h
@@ -0,0 +1,56 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This item widget manages a single file/directory
+//===========================================
+#ifndef _LUMINA_PANEL_USER_ITEM_WIDGET_H
+#define _LUMINA_PANEL_USER_ITEM_WIDGET_H
+
+#include <QFrame>
+#include <QLabel>
+#include <QToolButton>
+#include <QString>
+#include <QHBoxLayout>
+#include <QSize>
+#include <QDir>
+#include <QFile>
+#include <QMouseEvent>
+
+
+#include <LuminaXDG.h>
+
+class UserItemWidget : public QFrame{
+ Q_OBJECT
+public:
+ UserItemWidget(QWidget *parent=0, QString itemPath="", bool isDir=false);
+ UserItemWidget(QWidget *parent=0, XDGDesktop item= XDGDesktop());
+ ~UserItemWidget();
+
+private:
+ QToolButton *button;
+ QLabel *icon, *name;
+ bool isDirectory;
+
+ void createWidget();
+ void setupButton();
+
+private slots:
+ void buttonClicked();
+ void ItemClicked();
+
+protected:
+ void mouseReleaseEvent(QMouseEvent *event){
+ if(event->button() != Qt::NoButton){ ItemClicked(); }
+ }
+
+signals:
+ void NewShortcut();
+ void RemovedShortcut();
+ void RunItem(QString cmd);
+
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/userbutton/UserWidget.cpp b/lumina-desktop/panel-plugins/userbutton/UserWidget.cpp
new file mode 100644
index 00000000..f3dcad38
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/UserWidget.cpp
@@ -0,0 +1,215 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "UserWidget.h"
+#include "ui_UserWidget.h"
+#include "../../LSession.h"
+#include "../../AppMenu.h"
+
+UserWidget::UserWidget(QWidget* parent) : QWidget(parent), ui(new Ui::UserWidget){
+ ui->setupUi(this);
+ this->setContentsMargins(0,0,0,0);
+ sysapps = LSession::applicationMenu()->currentAppHash(); //get the raw info
+ //Setup the Icons
+ // - favorites tab
+ ui->tabWidget->setTabIcon(0, LXDG::findIcon("favorites","") );
+ ui->tabWidget->setTabText(0,"");
+ // - apps tab
+ ui->tabWidget->setTabIcon(1, LXDG::findIcon("system-run","") );
+ ui->tabWidget->setTabText(1,"");
+ // - home tab
+ ui->tabWidget->setTabIcon(2, LXDG::findIcon("user-home","") );
+ ui->tabWidget->setTabText(2,"");
+ // - config tab
+ ui->tabWidget->setTabIcon(3, LXDG::findIcon("preferences-system","") );
+ ui->tabWidget->setTabText(3,"");
+ ui->tool_fav_apps->setIcon( LXDG::findIcon("system-run","") );
+ ui->tool_fav_dirs->setIcon( LXDG::findIcon("folder","") );
+ ui->tool_fav_files->setIcon( LXDG::findIcon("document-multiple","") );
+ ui->tool_desktopsettings->setIcon( LXDG::findIcon("preferences-desktop","") );
+ ui->tool_config_screensaver->setIcon( LXDG::findIcon("preferences-desktop-screensaver","") );
+
+ //Connect the signals/slots
+ connect(ui->tool_desktopsettings, SIGNAL(clicked()), this, SLOT(openDeskSettings()) );
+ connect(ui->tool_config_screensaver, SIGNAL(clicked()), this, SLOT(openScreenSaverConfig()) );
+ connect(ui->tool_fav_apps, SIGNAL(clicked()), this, SLOT(FavChanged()) );
+ connect(ui->tool_fav_files, SIGNAL(clicked()), this, SLOT(FavChanged()) );
+ connect(ui->tool_fav_dirs, SIGNAL(clicked()), this, SLOT(FavChanged()) );
+ connect(ui->combo_app_cats, SIGNAL(currentIndexChanged(int)), this, SLOT(updateApps()) );
+ //Setup the special buttons
+ if(QFile::exists(APPSTORE)){
+ //Now load the info
+ bool ok = false;
+ XDGDesktop store = LXDG::loadDesktopFile(APPSTORE, ok);
+ if(ok){
+ ui->tool_app_store->setIcon( LXDG::findIcon(store.icon, "") );
+ ui->tool_app_store->setText( store.name );
+ connect(ui->tool_app_store, SIGNAL(clicked()), this, SLOT(openStore()) );
+ }
+ ui->tool_app_store->setVisible(ok); //availability
+ }else{
+ ui->tool_app_store->setVisible(false); //not available
+ }
+ if(QFile::exists(CONTROLPANEL)){
+ //Now load the info
+ bool ok = false;
+ XDGDesktop cpan = LXDG::loadDesktopFile(CONTROLPANEL, ok);
+ if(ok){
+ ui->tool_controlpanel->setIcon( LXDG::findIcon(cpan.icon, "") );
+ connect(ui->tool_controlpanel, SIGNAL(clicked()), this, SLOT(openControlPanel()) );
+ }
+ ui->tool_controlpanel->setVisible(ok); //availability
+ }else{
+ ui->tool_controlpanel->setVisible(false); //not available
+ }
+ if(QFile::exists(QTCONFIG)){
+ ui->tool_qtconfig->setVisible(true);
+ ui->tool_qtconfig->setIcon( LXDG::findIcon("preferences-desktop-theme","") );
+ connect(ui->tool_qtconfig, SIGNAL(clicked()), this, SLOT(openQtConfig()) );
+ }else{
+ ui->tool_qtconfig->setVisible(false);
+ }
+
+}
+
+UserWidget::~UserWidget(){
+}
+
+//===========
+// PRIVATE
+//===========
+void UserWidget::ClearScrollArea(QScrollArea *area){
+ QWidget *wgt = area->takeWidget();
+ delete wgt; //delete the widget and all children
+ area->setWidget( new QWidget() ); //create a new widget in the scroll area
+ area->widget()->setContentsMargins(0,0,0,0);
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setSpacing(2);
+ layout->setContentsMargins(3,1,3,1);
+ layout->setDirection(QBoxLayout::TopToBottom);
+ area->widget()->setLayout(layout);
+}
+
+//============
+// PRIVATE SLOTS
+//============
+void UserWidget::UpdateMenu(){
+ ui->tabWidget->setCurrentWidget(ui->tab_fav);
+ ui->tool_fav_apps->setChecked(true);
+ ui->tool_fav_dirs->setChecked(false);
+ ui->tool_fav_files->setChecked(false);
+ cfav = 0; //favorite apps
+ updateFavItems();
+ updateHome();
+ updateAppCategories();
+ updateApps();
+}
+
+void UserWidget::LaunchItem(QString cmd){
+ if(!cmd.isEmpty()){
+ qDebug() << "Launch Application:" << cmd;
+ LSession::LaunchApplication(cmd);
+ emit CloseMenu(); //so the menu container will close
+ }
+}
+
+void UserWidget::FavChanged(){
+ //uncheck the current item for a moment
+ if(cfav==0){ ui->tool_fav_apps->setChecked(false); }
+ else if(cfav==1){ ui->tool_fav_dirs->setChecked(false); }
+ if(cfav==2){ ui->tool_fav_files->setChecked(false); }
+ //Now check what other item is now the only one checked
+ if(ui->tool_fav_apps->isChecked() && !ui->tool_fav_dirs->isChecked() && !ui->tool_fav_files->isChecked() ){
+ cfav = 0;
+ }else if(!ui->tool_fav_apps->isChecked() && ui->tool_fav_dirs->isChecked() && !ui->tool_fav_files->isChecked() ){
+ cfav = 1;
+ }else if(!ui->tool_fav_apps->isChecked() && !ui->tool_fav_dirs->isChecked() && ui->tool_fav_files->isChecked() ){
+ cfav = 2;
+ }else{
+ //Re-check the old item (something invalid)
+ ui->tool_fav_apps->setChecked(cfav==0);
+ ui->tool_fav_dirs->setChecked(cfav==1);
+ ui->tool_fav_files->setChecked(cfav==2);
+ }
+ updateFavItems();
+}
+
+void UserWidget::updateFavItems(){
+ ClearScrollArea(ui->scroll_fav);
+ QStringList items;
+ QDir homedir = QDir( QDir::homePath()+"/Desktop");
+ if(ui->tool_fav_apps->isChecked()){ items = homedir.entryList(QStringList()<<"*.desktop", QDir::Files | QDir::NoDotAndDotDot, QDir::Name); }
+ else if(ui->tool_fav_dirs->isChecked()){ items = homedir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); }
+ else{
+ //Files
+ items = homedir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
+ for(int i=0; i<items.length(); i++){
+ if(items[i].endsWith(".desktop")){ items.removeAt(i); i--; }
+ }
+ }
+ for(int i=0; i<items.length(); i++){
+ UserItemWidget *it = new UserItemWidget(ui->scroll_fav->widget(), homedir.absoluteFilePath(items[i]), ui->tool_fav_dirs->isChecked());
+ ui->scroll_fav->widget()->layout()->addWidget(it);
+ connect(it, SIGNAL(RunItem(QString)), this, SLOT(LaunchItem(QString)) );
+ connect(it, SIGNAL(NewShortcut()), this, SLOT(updateFavItems()) );
+ connect(it, SIGNAL(RemovedShortcut()), this, SLOT(updateFavItems()) );
+ }
+ static_cast<QBoxLayout*>(ui->scroll_fav->widget()->layout())->addStretch();
+}
+
+//Apps Tab
+void UserWidget::updateAppCategories(){
+ ui->combo_app_cats->clear();
+ QStringList cats = sysapps->keys();
+ cats.sort();
+ for(int i=0; i<cats.length(); i++){
+ QString name, icon;
+ if(cats[i] == "Multimedia"){ name = tr("Multimedia"); icon = "applications-multimedia"; }
+ else if(cats[i] == "Development"){ name = tr("Development"); icon = "applications-development"; }
+ else if(cats[i] == "Education"){ name = tr("Education"); icon = "applications-education"; }
+ else if(cats[i] == "Game"){ name = tr("Games"); icon = "applications-games"; }
+ else if(cats[i] == "Graphics"){ name = tr("Graphics"); icon = "applications-graphics"; }
+ else if(cats[i] == "Network"){ name = tr("Network"); icon = "applications-internet"; }
+ else if(cats[i] == "Office"){ name = tr("Office"); icon = "applications-office"; }
+ else if(cats[i] == "Science"){ name = tr("Science"); icon = "applications-science"; }
+ else if(cats[i] == "Settings"){ name = tr("Settings"); icon = "preferences-system"; }
+ else if(cats[i] == "System"){ name = tr("System"); icon = "applications-system"; }
+ else if(cats[i] == "Utility"){ name = tr("Utility"); icon = "applications-utilities"; }
+ else{ name = tr("Unsorted"); icon = "applications-other"; }
+ ui->combo_app_cats->addItem( LXDG::findIcon(icon,""), name, cats[i] );
+ }
+}
+
+void UserWidget::updateApps(){
+ if(ui->combo_app_cats->currentIndex() < 0){ return; } //no cat
+ QString cat = ui->combo_app_cats->itemData( ui->combo_app_cats->currentIndex() ).toString();
+ QList<XDGDesktop> items = sysapps->value(cat);
+ ClearScrollArea(ui->scroll_apps);
+ for(int i=0; i<items.length(); i++){
+ UserItemWidget *it = new UserItemWidget(ui->scroll_apps->widget(), items[i]);
+ ui->scroll_apps->widget()->layout()->addWidget(it);
+ connect(it, SIGNAL(RunItem(QString)), this, SLOT(LaunchItem(QString)) );
+ connect(it, SIGNAL(NewShortcut()), this, SLOT(updateFavItems()) );
+ connect(it, SIGNAL(RemovedShortcut()), this, SLOT(updateFavItems()) );
+ }
+ static_cast<QBoxLayout*>(ui->scroll_apps->widget()->layout())->addStretch();
+}
+
+//Home Tab
+void UserWidget::updateHome(){
+ ClearScrollArea(ui->scroll_home);
+ QDir homedir = QDir::home();
+ QStringList items = homedir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
+ for(int i=0; i<items.length(); i++){
+ //qDebug() << "New Home subdir:" << homedir.absoluteFilePath(items[i]);
+ UserItemWidget *it = new UserItemWidget(ui->scroll_home->widget(), homedir.absoluteFilePath(items[i]), true);
+ ui->scroll_home->widget()->layout()->addWidget(it);
+ connect(it, SIGNAL(RunItem(QString)), this, SLOT(LaunchItem(QString)) );
+ connect(it, SIGNAL(NewShortcut()), this, SLOT(updateFavItems()) );
+ connect(it, SIGNAL(RemovedShortcut()), this, SLOT(updateFavItems()) );
+ }
+ static_cast<QBoxLayout*>(ui->scroll_home->widget()->layout())->addStretch();
+}
diff --git a/lumina-desktop/panel-plugins/userbutton/UserWidget.h b/lumina-desktop/panel-plugins/userbutton/UserWidget.h
new file mode 100644
index 00000000..5bc737a1
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/UserWidget.h
@@ -0,0 +1,82 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2014, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This panel plugin allows the user to quickly access user favorites and applications
+//===========================================
+#ifndef _LUMINA_PANEL_USER_BUTTON_WIDGET_H
+#define _LUMINA_PANEL_USER_BUTTON_WIDGET_H
+
+#include <QWidget>
+#include <QString>
+#include <QList>
+#include <QHash>
+#include <QVBoxLayout>
+#include <QScrollArea>
+
+#include <LuminaXDG.h>
+
+#include "UserItemWidget.h"
+
+#define APPSTORE QString("/usr/local/share/applications/softmanager.desktop")
+#define CONTROLPANEL QString("/usr/local/share/applications/pccontrol.desktop")
+#define QTCONFIG QString("/usr/local/bin/qtconfig-qt4")
+#define SSAVER QString("xscreensaver-demo")
+
+namespace Ui{
+ class UserWidget;
+};
+
+class UserWidget : public QWidget{
+ Q_OBJECT
+public:
+ UserWidget(QWidget *parent=0);
+ ~UserWidget();
+
+ void UpdateMenu();
+
+private:
+ Ui::UserWidget *ui;
+ QHash<QString, QList<XDGDesktop> > *sysapps;
+ int cfav; //current favorite category
+ void ClearScrollArea(QScrollArea *area);
+
+private slots:
+ void LaunchItem(QString cmd);
+
+ //Favorites Tab
+ void FavChanged(); //for ensuring radio-button-like behaviour
+ void updateFavItems();
+
+ //Apps Tab
+ void updateAppCategories();
+ void updateApps();
+
+ //Home Tab
+ void updateHome();
+
+ //Slots for the special buttons
+ void openStore(){
+ LaunchItem("lumina-open \""+APPSTORE+"\"");
+ }
+ void openControlPanel(){
+ LaunchItem("lumina-open \""+CONTROLPANEL+"\"");
+ }
+ void openDeskSettings(){
+ LaunchItem("lumina-config");
+ }
+ void openQtConfig(){
+ LaunchItem(QTCONFIG);
+ }
+ void openScreenSaverConfig(){
+ LaunchItem(SSAVER);
+ }
+
+signals:
+ void CloseMenu();
+
+};
+
+#endif \ No newline at end of file
diff --git a/lumina-desktop/panel-plugins/userbutton/UserWidget.ui b/lumina-desktop/panel-plugins/userbutton/UserWidget.ui
new file mode 100644
index 00000000..30625735
--- /dev/null
+++ b/lumina-desktop/panel-plugins/userbutton/UserWidget.ui
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UserWidget</class>
+ <widget class="QWidget" name="UserWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>237</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QWidget#UserWidget{background: transparent; }
+QWidget#tab_apps,#tab_fav,#tab_home,#tab_config{background: rgba(192,192,182,100); }</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_fav">
+ <attribute name="title">
+ <string notr="true">Favorites</string>
+ </attribute>
+ <attribute name="toolTip">
+ <string>Favorites</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="tool_fav_apps">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Favorite Applications</string>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_fav_dirs">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Favorite Directories</string>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_fav_files">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Favorite FIles</string>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scroll_fav">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>205</width>
+ <height>210</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_apps">
+ <attribute name="title">
+ <string notr="true">Apps</string>
+ </attribute>
+ <attribute name="toolTip">
+ <string>System Applications</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="combo_app_cats">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_app_store">
+ <property name="minimumSize">
+ <size>
+ <width>30</width>
+ <height>30</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scroll_apps">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents_2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>96</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_home">
+ <attribute name="title">
+ <string notr="true">Home</string>
+ </attribute>
+ <attribute name="toolTip">
+ <string>Home</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QScrollArea" name="scroll_home">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents_3">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>96</width>
+ <height>26</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_config">
+ <attribute name="title">
+ <string notr="true">Config</string>
+ </attribute>
+ <attribute name="toolTip">
+ <string>Desktop Preferences</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QToolButton" name="tool_controlpanel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Control Panel</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_desktopsettings">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Desktop Appearance/Plugins</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_qtconfig">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Application Appearance</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_config_screensaver">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Screensaver Settings</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>141</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
bgstack15