diff options
Diffstat (limited to 'lumina-desktop/panel-plugins')
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> |