aboutsummaryrefslogtreecommitdiff
path: root/desktop-utilities/lumina-terminal
diff options
context:
space:
mode:
Diffstat (limited to 'desktop-utilities/lumina-terminal')
-rw-r--r--desktop-utilities/lumina-terminal/TermWindow.cpp256
-rw-r--r--desktop-utilities/lumina-terminal/TermWindow.h66
-rw-r--r--desktop-utilities/lumina-terminal/TerminalWidget.cpp83
-rw-r--r--desktop-utilities/lumina-terminal/TerminalWidget.h36
-rw-r--r--desktop-utilities/lumina-terminal/TrayIcon.cpp172
-rw-r--r--desktop-utilities/lumina-terminal/TrayIcon.h59
-rw-r--r--desktop-utilities/lumina-terminal/lumina-terminal.pro110
-rw-r--r--desktop-utilities/lumina-terminal/main.cpp47
8 files changed, 829 insertions, 0 deletions
diff --git a/desktop-utilities/lumina-terminal/TermWindow.cpp b/desktop-utilities/lumina-terminal/TermWindow.cpp
new file mode 100644
index 00000000..4fc7fab5
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TermWindow.cpp
@@ -0,0 +1,256 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "TermWindow.h"
+//#include "ui_TermWindow.h"
+
+#include <QDesktopWidget>
+#include <QDebug>
+#include <QTimer>
+#include <QApplication>
+#include <QVBoxLayout>
+#include "TerminalWidget.h"
+
+// ===============
+// PUBLIC
+// ===============
+TermWindow::TermWindow() : QWidget(0, Qt::Window | Qt::BypassWindowManagerHint){//, ui(new Ui::TermWindow){
+ CLOSING = false; //internal flag
+ //Create the Window
+ this->setLayout(new QVBoxLayout());
+ this->setCursor(Qt::SplitVCursor);
+ tabWidget = new QTabWidget(this);
+ tabWidget->clear(); //just in case
+ tabWidget->setCursor(Qt::ArrowCursor);
+ tabWidget->setTabBarAutoHide(true);
+ tabWidget->setTabsClosable(true);
+ tabWidget->setMovable(true);
+ tabWidget->setUsesScrollButtons(true);
+ this->layout()->addWidget(tabWidget);
+ //Setup the animation
+ ANIM = new QPropertyAnimation(this, "geometry", this);
+ ANIM->setDuration(300); //1/3 second animation
+ connect(ANIM, SIGNAL(finished()), this, SLOT(AnimFinished()) );
+ //Create the keyboard shortcuts
+ hideS = new QShortcut(QKeySequence(Qt::Key_Escape),this);
+ closeS = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q),this);
+ newTabS = new QShortcut(QKeySequence::AddTab,this);
+ closeTabS = new QShortcut(QKeySequence::Close,this);
+ //Connect the signals/slots
+ connect(tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(Close_Tab(int)) );
+ connect(closeTabS, SIGNAL(activated()), this, SLOT(Close_Tab()) );
+ connect(newTabS, SIGNAL(activated()), this, SLOT(New_Tab()) );
+ connect(hideS, SIGNAL(activated()), this, SLOT(HideWindow()) );
+ connect(closeS, SIGNAL(activated()), this, SLOT(CloseWindow()) );
+
+ //Now set the defaults
+ screennum = 0; //default value
+ setTopOfScreen(true); //default value
+ //this->resize(this->width(),300);
+ //this->setMinimumSize(20, 300);
+
+}
+
+
+TermWindow::~TermWindow(){
+
+}
+
+void TermWindow::cleanup(){
+ //called right before the window is closed
+ //Make sure to close any open tabs/processes
+ CLOSING = true;
+ for(int i=0; i<tabWidget->count(); i++){
+ static_cast<TerminalWidget*>(tabWidget->widget(i))->aboutToClose();
+ }
+}
+
+void TermWindow::OpenDirs(QStringList dirs){
+ for(int i=0; i<dirs.length(); i++){
+ //Open a new tab for each directory
+ TerminalWidget *page = new TerminalWidget(tabWidget, dirs[i]);
+ QString ID = GenerateTabID();
+ page->setWhatsThis(ID);
+ tabWidget->addTab(page, ID);
+ qDebug() << "New Tab:" << ID << dirs[i];
+ connect(page, SIGNAL(ProcessClosed(QString)), this, SLOT(Close_Tab(QString)) );
+ }
+}
+
+void TermWindow::setCurrentScreen(int num){
+ screennum = num;
+ QTimer::singleShot(0,this, SLOT(ReShowWindow()));
+}
+
+void TermWindow::setTopOfScreen(bool ontop){
+ onTop = ontop;
+ this->layout()->setContentsMargins(0, (onTop ? 0 : 3), 0, (onTop ? 3 : 0));
+ tabWidget->setTabPosition(onTop ? QTabWidget::South : QTabWidget::North);
+ QTimer::singleShot(0,this, SLOT(ReShowWindow()));
+}
+
+// =======================
+// PUBLIC SLOTS
+// =======================
+void TermWindow::ShowWindow(){
+ this->hide();
+ QApplication::processEvents();
+ CalculateGeom();
+ //Now setup the animation
+ animRunning = 1;
+ ANIM->setEndValue(this->geometry());
+ if(onTop){ //use top edge
+ ANIM->setStartValue( QRect(this->x(), this->y(), this->width(), 0) ); //same location - no height
+ }else{
+ ANIM->setStartValue( QRect(this->x(), this->geometry().bottom(), this->width(), 0) ); //same location - no height
+ }
+ this->show();
+ ANIM->start();
+}
+
+void TermWindow::HideWindow(){
+ //Now setup the animation
+ //Note: Do *not* use the private settings/variables because it may be changing right now - use the current geometry *ONLY*
+ animRunning = 0;
+ ANIM->setStartValue(this->geometry());
+ QDesktopWidget *desk = QApplication::desktop();
+ int screen = desk->screenNumber(this); //which screen it is currently on
+ if(desk->availableGeometry(screen).top() == this->geometry().top()){ //use top edge
+ ANIM->setEndValue( QRect(this->x(), this->y(), this->width(), 0) ); //same location - no height
+ }else{
+ ANIM->setEndValue( QRect(this->x(), this->y()+this->height(), this->width(), 0) ); //same location - no height
+ }
+ this->show();
+ ANIM->start();
+}
+
+void TermWindow::CloseWindow(){
+ //Now setup the animation
+ animRunning = 2;
+ ANIM->setStartValue(this->geometry());
+ if(onTop){ //use top edge
+ ANIM->setEndValue( QRect(this->x(), this->y(), this->width(), 0) ); //same location - no height
+ }else{
+ ANIM->setEndValue( QRect(this->x(), this->geometry().bottom(), this->width(), 0) ); //same location - no height
+ }
+ this->show();
+ ANIM->start();
+}
+
+void TermWindow::ReShowWindow(){
+ if(this->isVisible()){
+ HideWindow(); //start with same animation as hide
+ animRunning = 3; //flag as a re-show (hide, then show);
+ }else{
+ //Already hidden, just show it
+ ShowWindow();
+ }
+}
+// =======================
+// PRIVATE
+// =======================
+void TermWindow::CalculateGeom(){
+ QDesktopWidget *desk = QApplication::desktop();
+ if(desk->screenCount() <= screennum){ screennum = desk->primaryScreen(); } //invalid screen detected
+ //Now align the window with the proper screen edge
+ QRect workarea = desk->availableGeometry(screennum); //this respects the WORKAREA property
+ if(onTop){
+ this->setGeometry( workarea.x(), workarea.y(), workarea.width(), this->height()); //maintain current hight of window
+
+ }else{
+ this->setGeometry( workarea.x(), workarea.y() + workarea.height() - this->height(), workarea.width(), this->height()); //maintain current hight of window
+ }
+ this->setFixedWidth(this->width()); //Make sure the window is not re-sizeable in the width dimension
+ this->setMinimumHeight(0);
+}
+
+QString TermWindow::GenerateTabID(){
+ //generate a unique ID for this new tab
+ int num = 1;
+ for(int i=0; i<tabWidget->count(); i++){
+ if(tabWidget->widget(i)->whatsThis().toInt() >= num){ num = tabWidget->widget(i)->whatsThis().toInt()+1; }
+ }
+ return QString::number(num);
+}
+
+// =======================
+// PRIVATE SLOTS
+// =======================
+
+//Tab Interactions
+void TermWindow::New_Tab(){
+ OpenDirs(QStringList() << QDir::homePath());
+}
+
+void TermWindow::Close_Tab(int tab){
+ //qDebug() << "Close Tab:" << tab;
+ if(tab<0){ tab = tabWidget->currentIndex(); }
+ static_cast<TerminalWidget*>(tabWidget->widget(tab))->aboutToClose();
+ delete tabWidget->widget(tab); //delete the page within the tag
+ tabWidget->removeTab(tab); // remove the tab itself
+ //Make sure there is always at least one tab
+ if(tabWidget->count() < 1){
+ if(CLOSING){ emit TerminalFinished(); }
+ else{ New_Tab(); }
+ }
+}
+
+void TermWindow::Close_Tab(QString ID){
+ //Close a tab based on it's ID instead of it's tab number
+ for(int i=0; i<tabWidget->count(); i++){
+ if(tabWidget->widget(i)->whatsThis()==ID){
+ Close_Tab(i);
+ return; //all done
+ }
+ }
+}
+
+//Animation finishing
+void TermWindow::AnimFinished(){
+ if(animRunning <0){ return; } //nothing running
+ if(animRunning==0){
+ //Hide Event
+ this->hide(); //need to hide the whole thing now
+ this->setGeometry( ANIM->startValue().toRect() ); //reset back to initial size after hidden
+ emit TerminalHidden();
+ }else if(animRunning==1){
+ //Show Event
+ this->activateWindow();
+ tabWidget->currentWidget()->setFocus();
+ emit TerminalVisible();
+ }else if(animRunning==2){
+ //Close Event
+ this->hide(); //need to hide the whole thing now
+ emit TerminalClosed();
+ }else if(animRunning>2){
+ //Re-Show event
+ this->hide();
+ this->setGeometry( ANIM->startValue().toRect() ); //reset back to initial size after hidden
+ //Now re-show it
+ QTimer::singleShot(0,this, SLOT(ShowWindow()));
+ }
+ animRunning = -1; //done
+}
+
+// ===================
+// PROTECTED
+// ===================
+void TermWindow::mouseMoveEvent(QMouseEvent *ev){
+ //Note: With mouse tracking turned off, this event only happens when the user is holding down the mouse button
+ if(onTop){
+ //Move the bottom edge to the current point
+ if( (ev->globalPos().y() - this->y()) < 50){ return; } //quick check that the window is not smaller than 20 pixels
+ QRect geom = this->geometry();
+ geom.setBottom(ev->globalPos().y());
+ this->setGeometry(geom);
+ }else{
+ //Move the top edge to the current point
+ if( (this->y() + this->height() -ev->globalPos().y()) < 50){ return; } //quick check that the window is not smaller than 20 pixels
+ QRect geom = this->geometry();
+ geom.setTop(ev->globalPos().y());
+ this->setGeometry(geom);
+ }
+} \ No newline at end of file
diff --git a/desktop-utilities/lumina-terminal/TermWindow.h b/desktop-utilities/lumina-terminal/TermWindow.h
new file mode 100644
index 00000000..ae40928f
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TermWindow.h
@@ -0,0 +1,66 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_UTILITIES_TERMINAL_MAIN_WINDOW_H
+#define _LUMINA_DESKTOP_UTILITIES_TERMINAL_MAIN_WINDOW_H
+
+#include <QWidget>
+#include <QPropertyAnimation>
+#include <QTabWidget>
+#include <QDir>
+#include <QShortcut>
+#include <QMouseEvent>
+
+class TermWindow : public QWidget{
+ Q_OBJECT
+public:
+ TermWindow();
+ ~TermWindow();
+
+ void cleanup(); //called right before the window is closed
+ void OpenDirs(QStringList);
+
+ void setCurrentScreen(int num = 0);
+ void setTopOfScreen(bool ontop);
+
+public slots:
+ void ShowWindow();
+ void HideWindow();
+ void CloseWindow();
+ void ReShowWindow();
+
+private:
+ QTabWidget *tabWidget;
+ QShortcut *hideS, *closeS, *newTabS, *closeTabS;
+ int screennum;
+ bool onTop, CLOSING;
+ QPropertyAnimation *ANIM;
+ int animRunning; //internal flag for what animation is currently running
+
+ //Calculate the window geometry necessary based on screen/location
+ void CalculateGeom();
+ QString GenerateTabID();
+
+private slots:
+ //Tab Interactions
+ void New_Tab();
+ void Close_Tab(int tab = -1);
+ void Close_Tab(QString ID); //alternate form of the close routine - based on tab ID
+
+ //Animation finishing
+ void AnimFinished();
+
+protected:
+ void mouseMoveEvent(QMouseEvent*);
+
+signals:
+ void TerminalHidden();
+ void TerminalVisible();
+ void TerminalClosed();
+ void TerminalFinished();
+};
+
+#endif
diff --git a/desktop-utilities/lumina-terminal/TerminalWidget.cpp b/desktop-utilities/lumina-terminal/TerminalWidget.cpp
new file mode 100644
index 00000000..4cfd3849
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TerminalWidget.cpp
@@ -0,0 +1,83 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "TerminalWidget.h"
+
+#include <QProcessEnvironment>
+#include <QDebug>
+#include <QApplication>
+
+TerminalWidget::TerminalWidget(QWidget *parent, QString dir) : QTextEdit(parent){
+ //Setup the text widget
+ this->setLineWrapMode(QTextEdit::WidgetWidth);
+ this->setReadOnly(true); //the key event catch will do the process/widget forwarding
+ this->setPlainText("WARNING: This utility is still incomplete and does not function properly yet");
+ //Create/launch the process
+ PROC = new QProcess(this);
+ PROC->setProcessEnvironment(QProcessEnvironment::systemEnvironment());
+ PROC->setWorkingDirectory(dir);
+ PROC->setProcessChannelMode(QProcess::MergedChannels);
+ //Connect the signals/slots
+ connect(PROC, SIGNAL(readyReadStandardOutput()), this, SLOT(UpdateText()) );
+ connect(PROC, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(ShellClosed()) );
+ //Now start the shell
+ PROC->start( PROC->processEnvironment().value("SHELL","/bin/sh"), QIODevice::ReadWrite);
+
+}
+
+TerminalWidget::~TerminalWidget(){
+
+}
+
+void TerminalWidget::aboutToClose(){
+ if(PROC->state()!=QProcess::NotRunning){ PROC->close(); }
+ if(PROC->state()!=QProcess::NotRunning){ PROC->kill(); }
+ if(PROC->state()!=QProcess::NotRunning){ PROC->terminate(); }
+}
+
+// ==================
+// PRIVATE SLOTS
+// ==================
+void TerminalWidget::UpdateText(){
+ while(PROC->canReadLine()){
+ QString line = PROC->readLine();
+ this->insertPlainText( line );
+ }
+}
+
+void TerminalWidget::ShellClosed(){
+ emit ProcessClosed(this->whatsThis());
+}
+
+// ==================
+// PROTECTED
+// ==================
+void TerminalWidget::keyPressEvent(QKeyEvent *ev){
+ //The way this works is by printing the keys directly to the text edit widget
+ // While also keeping an internal "buffer" of the input string so it can all be written to the process at the same time
+
+ QString key = ev->text();
+ //Check for special key combinations first
+ switch(ev->key()){
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ //send the current input buffer to the process
+ qDebug() << "Write to process:" << inBuffer;
+ this->insertPlainText("\n");
+ PROC->write( QString(inBuffer+"\n").toLocal8Bit() );
+ inBuffer.clear();
+ qDebug() << "Current Dir:" << PROC->workingDirectory();
+ break;
+ case Qt::Key_Backspace:
+ inBuffer.chop(1);
+ break;
+ default:
+ this->insertPlainText(key);
+ inBuffer.append(key);
+ }
+
+ ev->ignore();
+} \ No newline at end of file
diff --git a/desktop-utilities/lumina-terminal/TerminalWidget.h b/desktop-utilities/lumina-terminal/TerminalWidget.h
new file mode 100644
index 00000000..b16d298d
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TerminalWidget.h
@@ -0,0 +1,36 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_UTILITIES_TERMINAL_PROCESS_WIDGET_H
+#define _LUMINA_DESKTOP_UTILITIES_TERMINAL_PROCESS_WIDGET_H
+
+#include <QTextEdit>
+#include <QProcess>
+#include <QKeyEvent>
+
+class TerminalWidget : public QTextEdit{
+ Q_OBJECT
+public:
+ TerminalWidget(QWidget *parent =0, QString dir="");
+ ~TerminalWidget();
+
+ void aboutToClose();
+
+private:
+ QProcess *PROC;
+ QString inBuffer;
+private slots:
+ void UpdateText();
+ void ShellClosed();
+
+signals:
+ void ProcessClosed(QString);
+
+protected:
+ void keyPressEvent(QKeyEvent *event);
+};
+
+#endif \ No newline at end of file
diff --git a/desktop-utilities/lumina-terminal/TrayIcon.cpp b/desktop-utilities/lumina-terminal/TrayIcon.cpp
new file mode 100644
index 00000000..14ea24b4
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TrayIcon.cpp
@@ -0,0 +1,172 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "TrayIcon.h"
+
+#include <QDir>
+#include <QDesktopWidget>
+
+#include <LuminaUtils.h>
+
+TrayIcon::TrayIcon() : QSystemTrayIcon(){
+ //Create the child widgets here
+ settings = new QSettings("lumina-desktop","lumina-terminal");
+ this->setContextMenu(new QMenu());
+ ScreenMenu = new QMenu();
+ connect(ScreenMenu, SIGNAL(triggered(QAction*)), this, SLOT(ChangeScreen(QAction*)) );
+ TERM = new TermWindow();
+ //Load the current settings
+ TERM->setTopOfScreen(settings->value("TopOfScreen",true).toBool());
+ TERM->setCurrentScreen(settings->value("OnScreen",0).toInt());
+ connect(TERM, SIGNAL(TerminalHidden()), this, SLOT(TermHidden()));
+ connect(TERM, SIGNAL(TerminalVisible()), this, SLOT(TermVisible()));
+ connect(TERM, SIGNAL(TerminalClosed()), this, SLOT(startCleanup()));
+ connect(TERM, SIGNAL(TerminalFinished()), this, SLOT(stopApplication()));
+ connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(TrayActivated(QSystemTrayIcon::ActivationReason)) );
+}
+
+TrayIcon::~TrayIcon(){
+ delete TERM;
+ delete ScreenMenu;
+}
+
+// =============
+// PUBLIC
+// =============
+void TrayIcon::parseInputs(QStringList inputs){
+ //Note that this is only run on the primary process - otherwise inputs are sent to the slotSingleInstance() below
+ termVisible = !inputs.contains("-toggle"); //will automatically show the terminal on first run, even if "-toggle" is set
+
+ setupContextMenu();
+ updateIcons();
+ inputs = adjustInputs(inputs); //will adjust termVisible as necessary
+ if(inputs.isEmpty()){ inputs << QDir::homePath(); } //always start up with one terminal minimum
+ TERM->OpenDirs(inputs);
+ if(termVisible){ QTimer::singleShot(0, TERM, SLOT(ShowWindow())); }
+}
+
+// =================
+// PUBLIC SLOTS
+// =================
+void TrayIcon::slotSingleInstance(QStringList inputs){
+ //Note that this is only run for a secondary process forwarding its inputs
+ qDebug() << "Single Instance Event:" << inputs << termVisible;
+ bool visible = termVisible;
+ inputs = adjustInputs(inputs); //will adjust termVisible as necessary
+ if(!inputs.isEmpty()){ TERM->OpenDirs(inputs); }
+ //Only adjust the window if there was a change in the visibility status
+ qDebug() << "Set Visible:" << termVisible;
+ if(!visible && termVisible){ QTimer::singleShot(0, TERM, SLOT(ShowWindow())); }
+ else if(visible && !termVisible){ QTimer::singleShot(0, TERM, SLOT(HideWindow())); }
+}
+
+void TrayIcon::updateIcons(){
+ this->setIcon(LXDG::findIcon("utilities-terminal",""));
+}
+
+// ================
+// PRIVATE
+// ================
+QStringList TrayIcon::adjustInputs(QStringList inputs){
+ bool hasHide = false;
+ //Look for the special CLI flags just for the tray icon and trim them out
+ for(int i=0; i<inputs.length(); i++){
+ if(inputs[i]=="-toggle"){ hasHide = termVisible; inputs.removeAt(i); i--; } //toggle the visibility
+ else if(inputs[i]=="-show"){ hasHide = false; inputs.removeAt(i); i--; } //change the visibility
+ else if(inputs[i]=="-hide"){ hasHide = true; inputs.removeAt(i); i--; } //change the visibility
+ else{
+ //Must be a directory - convert to an absolute path and check for existance
+ inputs[i] = LUtils::PathToAbsolute(inputs[i]);
+ QFileInfo info(inputs[i]);
+ if(!info.exists()){
+ qDebug() << "Directory does not exist: " << inputs[i];
+ inputs.removeAt(i);
+ i--;
+ }else if(!info.isDir()){
+ //Must be some kind of file, open the parent directory
+ inputs[i] = inputs[i].section("/",0,-2);
+ }
+ }
+ }
+ termVisible = !hasHide;
+ return inputs;
+}
+
+// ================
+// PRIVATE SLOTS
+// ================
+void TrayIcon::startCleanup(){
+ TERM->cleanup();
+}
+
+void TrayIcon::stopApplication(){
+ QApplication::exit(0);
+}
+
+void TrayIcon::ChangeTopBottom(bool ontop){
+ TERM->setTopOfScreen(ontop);
+ settings->setValue("TopOfScreen",ontop); //save for later
+}
+
+void TrayIcon::ChangeScreen(QAction *act){
+ int screen = act->whatsThis().toInt();
+ TERM->setCurrentScreen(screen);
+ settings->setValue("OnScreen",screen);
+ updateScreenMenu();
+}
+
+void TrayIcon::setupContextMenu(){
+ this->contextMenu()->clear();
+ this->contextMenu()->addAction(LXDG::findIcon("edit-select",""), tr("Trigger Terminal"), this, SLOT(ToggleVisibility()) );
+ this->contextMenu()->addSeparator();
+ QAction * act = this->contextMenu()->addAction(tr("Top of Screen"), this, SLOT(ChangeTopBottom(bool)) );
+ act->setCheckable(true);
+ act->setChecked(settings->value("TopOfScreen",true).toBool() );
+ this->contextMenu()->addMenu(ScreenMenu);
+ this->contextMenu()->addSeparator();
+ this->contextMenu()->addAction(LXDG::findIcon("application-exit",""), tr("Close Terminal"), this, SLOT(stopApplication()) );
+ updateScreenMenu();
+}
+
+void TrayIcon::updateScreenMenu(){
+ ScreenMenu->clear();
+ QDesktopWidget *desk = QApplication::desktop();
+ int cscreen = settings->value("OnScreen",0).toInt();
+ if(cscreen>=desk->screenCount()){ cscreen = desk->primaryScreen(); }
+ ScreenMenu->setTitle(tr("Move To Monitor"));
+ for(int i=0; i<desk->screenCount(); i++){
+ if(i!=cscreen){
+ QAction *act = new QAction( QString(tr("Monitor %1")).arg(QString::number(i+1)),ScreenMenu);
+ act->setWhatsThis(QString::number(i));
+ ScreenMenu->addAction(act);
+ }
+ }
+ ScreenMenu->setVisible(!ScreenMenu->isEmpty());
+}
+
+void TrayIcon::TrayActivated(QSystemTrayIcon::ActivationReason reason){
+ switch(reason){
+ case QSystemTrayIcon::Context:
+ this->contextMenu()->popup(this->geometry().center());
+ break;
+ default:
+ ToggleVisibility();
+ }
+}
+
+//Slots for the window visibility
+void TrayIcon::ToggleVisibility(){
+ if(termVisible){ QTimer::singleShot(0, TERM, SLOT(HideWindow())); }
+ else{ QTimer::singleShot(0, TERM, SLOT(ShowWindow())); }
+}
+
+void TrayIcon::TermHidden(){
+ termVisible = false;
+}
+
+void TrayIcon::TermVisible(){
+ termVisible = true;
+} \ No newline at end of file
diff --git a/desktop-utilities/lumina-terminal/TrayIcon.h b/desktop-utilities/lumina-terminal/TrayIcon.h
new file mode 100644
index 00000000..961aaa90
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/TrayIcon.h
@@ -0,0 +1,59 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_DESKTOP_UTILITIES_TERMINAL_TRAY_ICON_H
+#define _LUMINA_DESKTOP_UTILITIES_TERMINAL_TRAY_ICON_H
+// QT Includes
+#include <QApplication>
+#include <QSystemTrayIcon>
+#include <QMenu>
+#include <QTimer>
+#include <QSettings>
+
+#include <LuminaXDG.h>
+
+#include "TermWindow.h"
+
+class TrayIcon : public QSystemTrayIcon {
+ Q_OBJECT
+
+public:
+ TrayIcon();
+ ~TrayIcon();
+
+ //First run
+ void parseInputs(QStringList); //Note that this is only run on the primary process - otherwise it gets sent to the singleInstance slot below
+
+public slots:
+ void slotSingleInstance(QStringList inputs = QStringList());
+ void updateIcons();
+
+private:
+ bool termVisible;
+ TermWindow *TERM;
+ QMenu *ScreenMenu;
+ QStringList adjustInputs(QStringList);
+ QSettings *settings;
+private slots:
+ //Action Buttons
+ void startCleanup();
+ void stopApplication();
+ void ChangeTopBottom(bool ontop);
+ void ChangeScreen(QAction*);
+
+ //Tray Updates
+ void setupContextMenu();
+ void updateScreenMenu();
+ void TrayActivated(QSystemTrayIcon::ActivationReason);
+
+ //Slots for the window visibility
+ void ToggleVisibility();
+ void TermHidden();
+ void TermVisible();
+
+};
+
+#endif
diff --git a/desktop-utilities/lumina-terminal/lumina-terminal.pro b/desktop-utilities/lumina-terminal/lumina-terminal.pro
new file mode 100644
index 00000000..82a5f8a4
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/lumina-terminal.pro
@@ -0,0 +1,110 @@
+TEMPLATE = app
+LANGUAGE = C++
+QT += core gui widgets network
+CONFIG += qt warn_on release
+
+isEmpty(PREFIX) {
+ PREFIX = /usr/local
+}
+TARGET = lumina-terminal
+target.path = $$DESTDIR$$PREFIX/bin
+
+isEmpty(LIBPREFIX) {
+ LIBPREFIX = $$PREFIX/lib
+}
+
+HEADERS += TrayIcon.h \
+ TermWindow.h \
+ TerminalWidget.h
+
+SOURCES += main.cpp \
+ TrayIcon.cpp \
+ TermWindow.cpp \
+ TerminalWidget.cpp
+
+
+INCLUDEPATH += ../../libLumina $$PREFIX/include
+LIBS += -L../../libLumina -L$$LIBPREFIX -lLuminaUtils
+
+isEmpty(QT5LIBDIR) {
+ QT5LIBDIR = $$PREFIX/lib/qt5
+}
+
+LRELEASE = $$QT5LIBDIR/bin/lrelease
+
+
+QMAKE_LIBDIR = ../libLumina
+DEPENDPATH += ../../libLumina
+
+TRANSLATIONS = i18n/lumina-terminal_af.ts \
+ i18n/lumina-terminal_ar.ts \
+ i18n/lumina-terminal_az.ts \
+ i18n/lumina-terminal_bg.ts \
+ i18n/lumina-terminal_bn.ts \
+ i18n/lumina-terminal_bs.ts \
+ i18n/lumina-terminal_ca.ts \
+ i18n/lumina-terminal_cs.ts \
+ i18n/lumina-terminal_cy.ts \
+ i18n/lumina-terminal_da.ts \
+ i18n/lumina-terminal_de.ts \
+ i18n/lumina-terminal_el.ts \
+ i18n/lumina-terminal_en_GB.ts \
+ i18n/lumina-terminal_en_ZA.ts \
+ i18n/lumina-terminal_es.ts \
+ i18n/lumina-terminal_et.ts \
+ i18n/lumina-terminal_eu.ts \
+ i18n/lumina-terminal_fa.ts \
+ i18n/lumina-terminal_fi.ts \
+ i18n/lumina-terminal_fr.ts \
+ i18n/lumina-terminal_fr_CA.ts \
+ i18n/lumina-terminal_gl.ts \
+ i18n/lumina-terminal_he.ts \
+ i18n/lumina-terminal_hi.ts \
+ i18n/lumina-terminal_hr.ts \
+ i18n/lumina-terminal_hu.ts \
+ i18n/lumina-terminal_id.ts \
+ i18n/lumina-terminal_is.ts \
+ i18n/lumina-terminal_it.ts \
+ i18n/lumina-terminal_ja.ts \
+ i18n/lumina-terminal_ka.ts \
+ i18n/lumina-terminal_ko.ts \
+ i18n/lumina-terminal_lt.ts \
+ i18n/lumina-terminal_lv.ts \
+ i18n/lumina-terminal_mk.ts \
+ i18n/lumina-terminal_mn.ts \
+ i18n/lumina-terminal_ms.ts \
+ i18n/lumina-terminal_mt.ts \
+ i18n/lumina-terminal_nb.ts \
+ i18n/lumina-terminal_nl.ts \
+ i18n/lumina-terminal_pa.ts \
+ i18n/lumina-terminal_pl.ts \
+ i18n/lumina-terminal_pt.ts \
+ i18n/lumina-terminal_pt_BR.ts \
+ i18n/lumina-terminal_ro.ts \
+ i18n/lumina-terminal_ru.ts \
+ i18n/lumina-terminal_sk.ts \
+ i18n/lumina-terminal_sl.ts \
+ i18n/lumina-terminal_sr.ts \
+ i18n/lumina-terminal_sv.ts \
+ i18n/lumina-terminal_sw.ts \
+ i18n/lumina-terminal_ta.ts \
+ i18n/lumina-terminal_tg.ts \
+ i18n/lumina-terminal_th.ts \
+ i18n/lumina-terminal_tr.ts \
+ i18n/lumina-terminal_uk.ts \
+ i18n/lumina-terminal_uz.ts \
+ i18n/lumina-terminal_vi.ts \
+ i18n/lumina-terminal_zh_CN.ts \
+ i18n/lumina-terminal_zh_HK.ts \
+ i18n/lumina-terminal_zh_TW.ts \
+ i18n/lumina-terminal_zu.ts
+
+dotrans.path=$$PREFIX/share/Lumina-DE/i18n/
+dotrans.extra=cd i18n && $${LRELEASE} -nounfinished *.ts && cp *.qm $(INSTALL_ROOT)$$PREFIX/share/Lumina-DE/i18n/
+
+INSTALLS += target dotrans
+
+NO_I18N{
+ INSTALLS -= dotrans
+}
+
diff --git a/desktop-utilities/lumina-terminal/main.cpp b/desktop-utilities/lumina-terminal/main.cpp
new file mode 100644
index 00000000..c117b8fb
--- /dev/null
+++ b/desktop-utilities/lumina-terminal/main.cpp
@@ -0,0 +1,47 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2015, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include <QSystemTrayIcon>
+#include <QDebug>
+
+#include <LuminaSingleApplication.h>
+#include <LuminaThemes.h>
+
+#include <unistd.h>
+
+#include "TrayIcon.h"
+int main(int argc, char *argv[]) {
+ LTHEME::LoadCustomEnvSettings();
+ LSingleApplication a(argc, argv, "lumina-terminal");
+ if( !a.isPrimaryProcess() ){ return 0; } //poked the current process instead
+
+ //First make sure a system tray is available
+ qDebug() << "Checking for system tray";
+ bool ready = false;
+ for(int i=0; i<60 && !ready; i++){
+ ready = QSystemTrayIcon::isSystemTrayAvailable();
+ if(!ready){
+ //Pause for 5 seconds
+ sleep(5); //don't worry about stopping event handling - nothing running yet
+ }
+ }
+ if(!ready){
+ qDebug() << "Could not find any available system tray after 5 minutes: exiting....";
+ return 1;
+ }
+
+ //Now go ahead and setup the app
+ LuminaThemeEngine theme(&a);
+ QApplication::setQuitOnLastWindowClosed(false);
+
+ //Now start the tray icon
+ TrayIcon tray;
+ QObject::connect(&a, SIGNAL(InputsAvailable(QStringList)), &tray, SLOT(slotSingleInstance(QStringList)) );
+ QObject::connect(&theme, SIGNAL(updateIcons()), &tray, SLOT(updateIcons()) );
+ tray.parseInputs(a.inputlist);
+ tray.show();
+ return a.exec();
+}
bgstack15