diff options
14 files changed, 267 insertions, 23 deletions
diff --git a/src-qt5/core/libLumina/ExternalProcess.h b/src-qt5/core/libLumina/ExternalProcess.h index 1325247f..8329c361 100644 --- a/src-qt5/core/libLumina/ExternalProcess.h +++ b/src-qt5/core/libLumina/ExternalProcess.h @@ -13,17 +13,40 @@ #include <QProcess> #include <QString> +#include <QTimer> +#include <QApplication> class ExternalProcess : public QProcess{ Q_OBJECT +private: + bool cursorRestored; + private slots: + void resetCursor(){ + if(!cursorRestored){ + QApplication::restoreOverrideCursor(); + cursorRestored = true; + } + } + void processStarting(){ + if(!cursorRestored){ + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + QTimer::singleShot(15000, this, SLOT(resetCursor()) ); + } + } void processFinished(){ + if(!cursorRestored){ + QApplication::restoreOverrideCursor(); + cursorRestored = true; + } //Clean up this object this->deleteLater(); } + public: - ExternalProcess(QString logfile = "") : QProcess(){ + ExternalProcess(QString logfile = "", bool manageCursors = true) : QProcess(){ this->setProcessChannelMode(QProcess::MergedChannels); + cursorRestored = !manageCursors; if(logfile.isEmpty()){ this->setStandardOutputFile(QProcess::nullDevice()); }else{ @@ -32,6 +55,7 @@ public: //Setup the connection for automatic cleanup connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished()) ); } + ~ExternalProcess(){ /*if(this->state() == QProcess::Running){ this->detach(); //about to close down the QProcess - detach the other program so it can continue functioning normally. diff --git a/src-qt5/core/libLumina/RootSubWindow.cpp b/src-qt5/core/libLumina/RootSubWindow.cpp new file mode 100644 index 00000000..f1d5fe61 --- /dev/null +++ b/src-qt5/core/libLumina/RootSubWindow.cpp @@ -0,0 +1,90 @@ +//=========================================== +// Lumina Desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "RootSubWindow.h" +#include <QDebug> + +// === PUBLIC === +RootSubWindow::RootSubWindow(QMdiArea *root, WId window, Qt::WindowFlags flags) : \ + QMdiSubWindow(0, flags){ + this->setAttribute(Qt::WA_DeleteOnClose); + //Create the QWindow and QWidget containers for the window + closing = false; + CID = window; + WIN = QWindow::fromWinId(CID); + WinWidget = QWidget::createWindowContainer( WIN, this); + this->setWidget(WinWidget); + //Hookup the signals/slots + connect(this, SIGNAL(aboutToActivate()), this, SLOT(aboutToActivate()) ); + connect(WIN, SIGNAL(windowTitleChanged(const QString&)), this, SLOT(setWindowTitle(const QString&)) ); + connect(WIN, SIGNAL(heightChanged(int)), this, SLOT(adjustHeight(int) )); + connect(WIN, SIGNAL(widthChanged(int)), this, SLOT(adjustWidth(int) )); + + qDebug() << "Initial Window Geometry:" << WIN->geometry(); + qDebug() << "Initial Widget Geometry:" << WinWidget->geometry(); + qDebug() << "Minimums:"; + qDebug() << " - Height:" << WIN->minimumHeight(); + qDebug() << " - Width:" << WIN->minimumWidth(); + + //this->resize(WinWidget->size()); + //Now add this window to the root QMdiArea + root->addSubWindow(this); +} + +RootSubWindow::~RootSubWindow(){ + +} + +WId RootSubWindow::id(){ + return CID; +} + +// === PRIVATE === + +// === PUBLIC SLOTS === +void RootSubWindow::clientClosed(){ + qDebug() << "Client Closed"; + closing = true; + this->close(); +} + +void RootSubWindow::clientHidden(){ + qDebug() << "Client Hidden"; + this->hide(); +} + +void RootSubWindow::clientShown(){ + qDebug() << "Client Shown"; + this->show(); +} + +// === PRIVATE SLOTS === +void RootSubWindow::aboutToActivate(){ + emit Activated(CID); //need to activate the subwindow - not the frame + WIN->requestActivate(); +} + +void RootSubWindow::adjustHeight(int val){ + qDebug() << "Adjust height:" << val; + WinWidget->resize(WinWidget->width(), val); +} + +void RootSubWindow::adjustWidth(int val){ + qDebug() << "Adjust Width:" << val; + WinWidget->resize(val, WinWidget->height()); +} + +// === PROTECTED === +void RootSubWindow::closeEvent(QCloseEvent *ev){ + if(!closing){ + qDebug() << "Close Window By Button:" << CID; + ev->ignore(); + WIN->destroy(); + }else{ + QMdiSubWindow::closeEvent(ev); + } + +} diff --git a/src-qt5/core/libLumina/RootSubWindow.h b/src-qt5/core/libLumina/RootSubWindow.h new file mode 100644 index 00000000..d4119ccc --- /dev/null +++ b/src-qt5/core/libLumina/RootSubWindow.h @@ -0,0 +1,50 @@ +//=========================================== +// Lumina Desktop source code +// Copyright (c) 2017, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This class embeds a native window +// within the RootWindow area +//=========================================== +#ifndef _LUMINA_ROOT_WINDOW_SUB_WINDOW_H +#define _LUMINA_ROOT_WINDOW_SUB_WINDOW_H + +#include <QMdiArea> +#include <QMdiSubWindow> +#include <QWindow> +#include <QWidget> +#include <QCloseEvent> + +class RootSubWindow : public QMdiSubWindow{ + Q_OBJECT +public: + RootSubWindow(QMdiArea *root, WId window, Qt::WindowFlags flags = Qt::WindowFlags()); + ~RootSubWindow(); + + WId id(); + +private: + WId CID; //client window ID + QWindow *WIN; //Embedded window container + QWidget *WinWidget; + bool closing; +public slots: + void clientClosed(); + void clientHidden(); + void clientShown(); + +private slots: + void aboutToActivate(); + void adjustHeight(int); + void adjustWidth(int); + +protected: + void closeEvent(QCloseEvent*); + +signals: + void Activated(WId); + +}; + +#endif diff --git a/src-qt5/core/libLumina/RootWindow.cpp b/src-qt5/core/libLumina/RootWindow.cpp index aa5957b5..57950a48 100644 --- a/src-qt5/core/libLumina/RootWindow.cpp +++ b/src-qt5/core/libLumina/RootWindow.cpp @@ -11,7 +11,7 @@ #include <QDebug> // === PUBLIC === -RootWindow::RootWindow() : QWidget(0, Qt::Window | Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint){ +RootWindow::RootWindow() : QMdiArea(0){ //QWidget(0, Qt::Window | Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint){ qRegisterMetaType<WId>("WId"); autoResizeTimer = 0; } @@ -166,13 +166,43 @@ void RootWindow::ChangeWallpaper(QString id, RootWindow::ScaleType scale, QStrin } +void RootWindow::NewWindow(WId win, Qt::WindowFlags flags){ + RootSubWindow *subwin = 0; + for(int i=0; i<WINDOWS.length() && subwin==0; i++){ + if(WINDOWS[i]->id() == win){ subwin = WINDOWS[i]; } + } + if(subwin==0){ + subwin = new RootSubWindow(this, win, flags); + WINDOWS << subwin; + } + subwin->show(); +} + +void RootWindow::ShowWindow(WId win){ + for(int i=0; i<WINDOWS.length(); i++){ + if(WINDOWS[i]->id() == win){ WINDOWS[i]->clientShown(); break; } + } +} + +void RootWindow::HideWindow(WId win){ + for(int i=0; i<WINDOWS.length(); i++){ + if(WINDOWS[i]->id() == win){ WINDOWS[i]->clientHidden(); break; } + } +} + +void RootWindow::CloseWindow(WId win){ + for(int i=0; i<WINDOWS.length(); i++){ + if(WINDOWS[i]->id() == win){ WINDOWS.takeAt(i)->clientClosed(); break; } + } +} + // === PRIVATE SLOTS === // === PROTECTED === void RootWindow::paintEvent(QPaintEvent *ev){ //qDebug() << "RootWindow: PaintEvent:" << ev->rect(); //<< QDateTime::currentDateTime()->toString(QDateTime::ShortDate); bool found = false; - QPainter painter(this); + QPainter painter(this->viewport()); for(int i=0; i<WALLPAPERS.length(); i++){ if(WALLPAPERS[i].area.intersects(ev->rect()) ){ found = true; diff --git a/src-qt5/core/libLumina/RootWindow.h b/src-qt5/core/libLumina/RootWindow.h index b371d239..a653d82a 100644 --- a/src-qt5/core/libLumina/RootWindow.h +++ b/src-qt5/core/libLumina/RootWindow.h @@ -18,8 +18,11 @@ #include <QTimer> #include <QApplication> #include <QPaintEvent> +#include <QMdiArea> -class RootWindow : public QWidget{ +#include "RootSubWindow.h" + +class RootWindow : public QMdiArea{ Q_OBJECT public: enum ScaleType{ SolidColor, Stretch, Full, Fit, Center, Tile, BottomLeft, BottomRight, BottomCenter, \ @@ -43,11 +46,19 @@ private: QList<screeninfo> WALLPAPERS; void updateScreenPixmap(screeninfo *info); //used for recalculating the wallpaper pixmap based on file/area/scale as needed + //Window Management + QList<RootSubWindow*> WINDOWS; + public slots: void ResizeRoot(); void ChangeWallpaper(QString id, RootWindow::ScaleType scale, QString file); //Note: for "SingleColor" scaling the "file" variable should be "rgb(R,G,B)" or "#hexcode" + void NewWindow(WId win, Qt::WindowFlags flags = Qt::WindowFlags()); + void ShowWindow(WId win); + void HideWindow(WId win); + void CloseWindow(WId win); + private slots: protected: diff --git a/src-qt5/core/libLumina/RootWindow.pri b/src-qt5/core/libLumina/RootWindow.pri index 7ef3efb0..fac1992d 100644 --- a/src-qt5/core/libLumina/RootWindow.pri +++ b/src-qt5/core/libLumina/RootWindow.pri @@ -1,7 +1,10 @@ # Files -SOURCES *= $${PWD}/RootWindow.cpp -HEADERS *= $${PWD}/RootWindow.h +SOURCES *= $${PWD}/RootWindow.cpp \ + $${PWD}/RootSubWindow.cpp + +HEADERS *= $${PWD}/RootWindow.h \ + $${PWD}/RootSubWindow.h INCLUDEPATH *= ${PWD} diff --git a/src-qt5/core/lumina-desktop-unified/LSession.cpp b/src-qt5/core/lumina-desktop-unified/LSession.cpp index cb0144d5..706c6006 100644 --- a/src-qt5/core/lumina-desktop-unified/LSession.cpp +++ b/src-qt5/core/lumina-desktop-unified/LSession.cpp @@ -41,7 +41,7 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu //this->setAttribute(Qt::AA_UseHighDpiPixmaps); //allow pixmaps to be scaled up as well as down //Now initialize the global objects (but do not start them yet) - Lumina::EFILTER = new EventFilter(); //Need the XCB Event filter + Lumina::EFILTER = new EventFilter(); //Need the XCB Event filter first Lumina::SETTINGS = new DesktopSettings(); Lumina::SS = new LScreenSaver(); //Lumina::WM = new LWindowManager(); @@ -60,7 +60,10 @@ LSession::LSession(int &argc, char ** argv) : LSingleApplication(argc, argv, "lu //Setup the various connections between the global classes // NOTE: Most of these connections will only become "active" as the global objects get started during the setupSession routine connect(Lumina::ROOTWIN, SIGNAL(RegisterVirtualRoot(WId)), Lumina::EFILTER, SLOT(RegisterVirtualRoot(WId)) ); - + connect(Lumina::EFILTER, SIGNAL(WindowCreated(WId)), Lumina::ROOTWIN, SLOT(NewWindow(WId)) ); + connect(Lumina::EFILTER, SIGNAL(WindowClosed(WId)), Lumina::ROOTWIN, SLOT(CloseWindow(WId)) ); + connect(Lumina::EFILTER, SIGNAL(WindowHidden(WId)), Lumina::ROOTWIN, SLOT(HideWindow(WId)) ); + connect(Lumina::EFILTER, SIGNAL(WindowShown(WId)), Lumina::ROOTWIN, SLOT(ShowWindow(WId)) ); } //end check for primary process } @@ -176,7 +179,7 @@ void LSession::setupSession(){ Lumina::SHORTCUTS->start(); //Startup the shortcut handler now //for(int i=0; i<4; i++){ LSession::processEvents(); } //Again, just a few event loops here so thing can settle before we close the splash screen //launchStartupApps(); - //QTimer::singleShot(500, this, SLOT(launchStartupApps()) ); + QTimer::singleShot(500, this, SLOT(launchStartupApps()) ); splash.hide(); LSession::processEvents(); splash.close(); @@ -279,7 +282,7 @@ void LSession::launchStartupApps(){ LOS::setScreenBrightness( tmp ); qDebug() << " - - Screen Brightness:" << QString::number(tmp)+"%"; } - QProcess::startDetached("nice lumina-open -autostart-apps"); + //ExternalProcess::launch("nice lumina-open -autostart-apps"); //Re-load the screen brightness and volume settings from the previous session // Wait until after the XDG-autostart functions, since the audio system might be started that way diff --git a/src-qt5/core/lumina-desktop-unified/global-includes.h b/src-qt5/core/lumina-desktop-unified/global-includes.h index 6a753cd1..ed687917 100644 --- a/src-qt5/core/lumina-desktop-unified/global-includes.h +++ b/src-qt5/core/lumina-desktop-unified/global-includes.h @@ -57,6 +57,7 @@ #include <LuminaSingleApplication.h> #include <DesktopSettings.h> #include <RootWindow.h> +#include <ExternalProcess.h> // Standard C includes #include <unistd.h> diff --git a/src-qt5/core/lumina-desktop-unified/lumina-desktop.pro b/src-qt5/core/lumina-desktop-unified/lumina-desktop.pro index 497ce635..1de8308d 100644 --- a/src-qt5/core/lumina-desktop-unified/lumina-desktop.pro +++ b/src-qt5/core/lumina-desktop-unified/lumina-desktop.pro @@ -17,6 +17,7 @@ include(../libLumina/LuminaSingleApplication.pri) include(../libLumina/LuminaThemes.pri) include(../libLumina/DesktopSettings.pri) include(../libLumina/RootWindow.pri) +include(../libLumina/ExternalProcess.pri) #include all the main individual source groups include(src-screensaver/screensaver.pri) diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.cpp index fa4af5ba..e363af01 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.cpp @@ -24,7 +24,7 @@ void DesktopContextMenu::UpdateMenu(){ for(int i=0; i<items.length(); i++){ if(items[i]=="terminal"){ this->addAction(LXDG::findIcon("utilities-terminal",""), tr("Terminal"))->setWhatsThis("lumina-open -terminal"); } else if(items[i]=="lockdesktop"){ this->addAction(LXDG::findIcon("system-lock-screen",""), tr("Lock Session"), this, SIGNAL(LockSession()) ); } - else if(items[i]=="filemanager"){ this->addAction( LXDG::findIcon("user-home",""), tr("Browse Files"))->setWhatsThis("lumina-open ~"); } + else if(items[i]=="filemanager"){ this->addAction( LXDG::findIcon("user-home",""), tr("Browse Files"))->setWhatsThis("lumina-open \""+QDir::homePath()+"\""); } //else if(items[i]=="applications"){ this->addMenu( LSession::handle()->applicationMenu() ); } else if(items[i]=="line"){ this->addSeparator(); } //else if(items[i]=="settings"){ this->addMenu( LSession::handle()->settingsMenu() ); } @@ -34,7 +34,7 @@ void DesktopContextMenu::UpdateMenu(){ QString file = items[i].section("::::",1,1).simplified(); XDGDesktop xdgf(file);// = LXDG::loadDesktopFile(file, ok); if(xdgf.type!=XDGDesktop::BAD){ - this->addAction( LXDG::findIcon(xdgf.icon,""), xdgf.name)->setWhatsThis(file); + this->addAction( LXDG::findIcon(xdgf.icon,""), xdgf.name)->setWhatsThis("lumina-open \""+file+"\""); }else{ qDebug() << "Could not load application file:" << file; } @@ -86,8 +86,9 @@ void DesktopContextMenu::start(){ // === PRIVATE SLOTS === void DesktopContextMenu::LaunchAction(QAction *act){ if(act->whatsThis().isEmpty() || act->parent()!=this ){ return; } + qDebug() << "Launch Menu Action:" << act->whatsThis(); QString cmd = act->whatsThis(); - emit LaunchApplication(cmd); + ExternalProcess::launch(cmd); } void DesktopContextMenu::showMenu(const QPoint &pt){ diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.h b/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.h index 1a4befc9..8b0509fb 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/ContextMenu.h @@ -30,7 +30,6 @@ private slots: void showMenu(const QPoint&); signals: - void LaunchApplication(QString); //cmd to run void LockSession(); void showLeaveDialog(); }; diff --git a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp index 4a192aa4..6660e41e 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.cpp @@ -132,13 +132,13 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag //============================== case XCB_KEY_PRESS: //This is a keyboard key press - qDebug() << "Key Press Event"; + //qDebug() << "Key Press Event"; stopevent = BlockInputEvent( ((xcb_key_press_event_t *) ev)->root ); //use the main "root" window - not the child widget if(!stopevent){ obj->emit KeyPressed( InputWindow(((xcb_key_press_event_t *) ev)->root), ((xcb_key_press_event_t *) ev)->detail ); } break; case XCB_KEY_RELEASE: //This is a keyboard key release - qDebug() << "Key Release Event"; + //qDebug() << "Key Release Event"; stopevent = BlockInputEvent( ((xcb_key_release_event_t *) ev)->root ); //use the main "root" window - not the child widget if(!stopevent){ obj->emit KeyReleased( InputWindow(((xcb_key_release_event_t *) ev)->root), ((xcb_key_release_event_t *) ev)->detail ); } break; @@ -183,24 +183,27 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag break; //============================== case XCB_MAP_NOTIFY: + qDebug() << "Window Map Event:" << ((xcb_map_notify_event_t *)ev)->window; + obj->emit WindowShown( ((xcb_map_notify_event_t *)ev)->window); break; //This is just a notification that a window was mapped - nothing needs to change here case XCB_MAP_REQUEST: qDebug() << "Window Map Request Event"; - obj->emit ModifyWindow( ((xcb_map_request_event_t *) ev)->window, Lumina::Show); + SetupNewWindow( ((xcb_map_request_event_t *) ev) ); break; //============================== case XCB_CREATE_NOTIFY: - qDebug() << "Window Create Event"; + //qDebug() << "Window Create Event"; break; //============================== case XCB_UNMAP_NOTIFY: - qDebug() << "Window Unmap Event"; - obj->emit ModifyWindow( ((xcb_unmap_notify_event_t *)ev)->window, Lumina::Hide); + qDebug() << "Window Unmap Event:" << ((xcb_unmap_notify_event_t *)ev)->window; + obj->emit WindowHidden( ((xcb_unmap_notify_event_t *)ev)->window); break; //============================== case XCB_DESTROY_NOTIFY: - qDebug() << "Window Closed Event"; + qDebug() << "Window Closed Event:" << ((xcb_destroy_notify_event_t *)ev)->window; if( !rmTrayApp( ((xcb_destroy_notify_event_t *) ev)->window ) ){ + qDebug() <<" - Non-tray window"; obj->emit WindowClosed( ((xcb_destroy_notify_event_t *) ev)->window ); } break; @@ -389,3 +392,27 @@ void XCBEventFilter::checkDamageID(WId id){ //Could check for window damage ID's - but we should not need this } } + +// WINDOW HANDLING FUNCTIONS +void XCBEventFilter::SetupNewWindow(xcb_map_request_event_t *ev){ + WId win = ev->window; + + bool ok = obj->XCB->WM_ManageWindow(win, true); + //Quick check if this is a transient window if we could not manage it directly + if(!ok){ + WId tran = obj->XCB->WM_ICCCM_GetTransientFor(win); + if(tran!=win && tran!=0){ + win = tran; + ok = obj->XCB->WM_ManageWindow(win); + } + } + qDebug() << "New Window:" << win << obj->XCB->WM_ICCCM_GetClass(win) << " Managed:" << ok; + obj->XCB->WM_Set_Active_Window(win); + //Determing the requested geometry/location/management within the event, + // and forward that on to the graphical embedding side of the WM + + + obj->emit WindowCreated(win); + //TEMPORARY FOR DEBUGGING + //obj->XCB->WM_ShowWindow(win); +} diff --git a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h index 9e76ba53..30dc925d 100644 --- a/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h +++ b/src-qt5/core/lumina-desktop-unified/src-events/LXcbEventFilter.h @@ -69,7 +69,9 @@ public slots: signals: void NewInputEvent(); - void NewManagedWindow(WId); + void WindowCreated(WId); + void WindowShown(WId); + void WindowHidden(WId); void WindowClosed(WId); void ModifyWindow(WId win, Lumina::WindowAction); @@ -120,6 +122,7 @@ private: void checkDamageID(WId); //Longer Event handling functions + void SetupNewWindow(xcb_map_request_event_t *ev); //bool ParseKeyPressEvent(); //bool ParseKeyReleaseEvent(); //bool ParseButtonPressEvent(); diff --git a/src-qt5/core/lumina-desktop-unified/src-screensaver/SSBaseWidget.cpp b/src-qt5/core/lumina-desktop-unified/src-screensaver/SSBaseWidget.cpp index 83b82ff8..9ad31f5c 100644 --- a/src-qt5/core/lumina-desktop-unified/src-screensaver/SSBaseWidget.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-screensaver/SSBaseWidget.cpp @@ -19,6 +19,7 @@ SSBaseWidget::SSBaseWidget(QWidget *parent, QSettings *set) : QWidget(parent){ this->setObjectName("LuminaBaseSSWidget"); ANIM = 0; this->setMouseTracking(true); + plugType="none"; } SSBaseWidget::~SSBaseWidget(){ @@ -51,7 +52,7 @@ void SSBaseWidget::startPainting(){ //Now list all the various plugins and start them appropriately QString style; if(cplug=="none"){ - style = "background: transparent;"; //show the underlying black parent widget + style = "background: black;"; //show the underlying black parent widget }else{ style = "background: black;"; } |