diff options
Diffstat (limited to 'lumina-desktop/panel-plugins/taskmanager')
5 files changed, 511 insertions, 0 deletions
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 |