diff options
Diffstat (limited to 'lumina-wm-INCOMPLETE')
-rw-r--r-- | lumina-wm-INCOMPLETE/GlobalDefines.h | 3 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LWindow.cpp | 151 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LWindow.h | 55 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LWindowManager.cpp | 155 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LWindowManager.h | 40 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LXcbEventFilter.cpp | 169 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/LXcbEventFilter.h | 46 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/WMSession.cpp | 14 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/WMSession.h | 6 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/lumina-wm.pro | 6 | ||||
-rw-r--r-- | lumina-wm-INCOMPLETE/main.cpp | 2 |
11 files changed, 486 insertions, 161 deletions
diff --git a/lumina-wm-INCOMPLETE/GlobalDefines.h b/lumina-wm-INCOMPLETE/GlobalDefines.h index b6e6587d..68cf927d 100644 --- a/lumina-wm-INCOMPLETE/GlobalDefines.h +++ b/lumina-wm-INCOMPLETE/GlobalDefines.h @@ -42,6 +42,7 @@ #include <QHostInfo> #include <QDesktopWidget> #include <QStyleOption> +#include <QThread> // libLumina includes #include <LuminaX11.h> @@ -62,7 +63,7 @@ //Global flags/structures namespace LWM{ //Flags/enumerations - enum WindowAction{MoveResize, Show, Hide, TryClose, Closed}; + enum WindowAction{MoveResize, Show, Hide, TryClose, Closed, WA_NONE}; //Data structures extern LXCB *SYSTEM; diff --git a/lumina-wm-INCOMPLETE/LWindow.cpp b/lumina-wm-INCOMPLETE/LWindow.cpp index 9d9f9fcd..ad34c4dd 100644 --- a/lumina-wm-INCOMPLETE/LWindow.cpp +++ b/lumina-wm-INCOMPLETE/LWindow.cpp @@ -6,45 +6,36 @@ //=========================================== #include "LWindow.h" -LWindow::LWindow(WId client) : QFrame(){ - activeState = LWindow::Normal; +LWindowFrame::LWindowFrame(WId client, QWidget *parent) : QFrame(parent, Qt::X11BypassWindowManagerHint){ + activeState = LWindowFrame::Normal; CID = client; - qDebug() << "New Window:" << CID << "Frame:" << this->winId(); + lastAction = LWM::WA_NONE; + Closing = false; + //qDebug() << "New Window:" << CID << "Frame:" << this->winId(); this->setMouseTracking(true); //need this to determine mouse location when not clicked this->setObjectName("LWindowFrame"); - this->setStyleSheet("LWindow#LWindowFrame{ border: 2px solid white; border-radius:3px; } QWidget#TitleBar{background: grey; } QLabel{ color: black; }"); - //this->setAttribute(Qt::WA_TranslucentBackground, true); - //this->setAttribute(Qt::WA_StyledBackground, true); - this->setWindowFlags(Qt::Window | Qt::FramelessWindowHint); //Qt::X11BypassWindowManagerHint); //ensure that this frame does not get a frame itself + this->setStyleSheet("LWindowFrame#LWindowFrame{ border: 2px solid white; border-radius:3px; } QWidget#TitleBar{background: grey; } QLabel{ color: black; }"); InitWindow(); //initially create all the child widgets + //LWM::SYSTEM->setupEventsForFrame(this->winId()); updateAppearance(); //this loads the appearance based on window/theme settings - QApplication::processEvents(); + //QApplication::processEvents(); //Now set the frame size on this window SyncSize(); - SyncText(); - //LWM::SYSTEM->RestoreWindow(CID); + SyncText(); this->show(); } -LWindow::~LWindow(){ - +LWindowFrame::~LWindowFrame(){ } // ================= -// PUBLIC -// ================= -//Return the ID of the managed window for the current graphics system (X11/Wayland/other) -WId LWindow::clientID(){ return CID; } - -bool LWindow::hasFrame(){ return this->isEnabled(); } - -// ================= // PRIVATE // ================= -void LWindow::InitWindow(){ +void LWindowFrame::InitWindow(){ anim = new QPropertyAnimation(this); //For simple window animations anim->setTargetObject(this); anim->setDuration(ANIMTIME); //In milliseconds + connect(anim, SIGNAL(finished()), this, SLOT(finishedAnimation()) ); titleBar = new QLabel(this); //This is the "container" for all the title buttons/widgets titleBar->setObjectName("TitleBar"); titleBar->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); @@ -91,15 +82,20 @@ void LWindow::InitWindow(){ VL->setAlignment(titleBar, Qt::AlignTop); VL->setContentsMargins(0,0,0,0); VL->setSpacing(0); + //Have the window take the same initial size of the client window + this->setGeometry( LWM::SYSTEM->WM_Window_Geom(CID) ); + qDebug() << "First Geom:" << this->geometry(); + if(this->width() < 100 && this->height() < 100){ this->resize(100,100); } + //Now embed the native window into the frame WIN = QWindow::fromWinId(CID); + WinWidget = QWidget::createWindowContainer( WIN, this); //WINBACK = new QBackingStore(WIN); //create a data backup for the widget - this->layout()->addWidget( QWidget::createWindowContainer( WIN, this) ); - //this->layout()-> //set the container as expanding - VL->setStretch(1,1); + //this->layout()->addWidget( WinWidget ); + //VL->setStretch(1,1); } -LWindow::ModState LWindow::getStateAtPoint(QPoint pt, bool setoffset){ +LWindowFrame::ModState LWindowFrame::getStateAtPoint(QPoint pt, bool setoffset){ //Note: pt should be in widget-relative coordinates, not global if(!this->layout()->geometry().contains(pt)){ //above the frame itself - need to figure out which quadrant it is in (8-directions) @@ -141,7 +137,7 @@ LWindow::ModState LWindow::getStateAtPoint(QPoint pt, bool setoffset){ return Normal; } -void LWindow::setMouseCursor(ModState state, bool override){ +void LWindowFrame::setMouseCursor(ModState state, bool override){ Qt::CursorShape shape; switch(state){ case Normal: @@ -185,40 +181,48 @@ void LWindow::setMouseCursor(ModState state, bool override){ // ========================== // WINDOW INTERACTIONS //========================== -void LWindow::SyncSize(){ +void LWindowFrame::SyncSize(bool fromwin){ //sync the window/frame geometries (generally only done before embedding the client window) int frame = this->frameWidth(); int TH = titleBar->height(); - //SYSTEM->SetFrameValues(CID, frame, frame, frame, frame); //Now load the information about the window and adjust the frame to match - lastGeom = LWM::SYSTEM->WindowGeometry(CID,false); + if(fromwin){ lastGeom = LWM::SYSTEM->WM_Window_Geom(CID); } + else{ lastGeom = this->geometry(); } qDebug() << "Initial Size:" << lastGeom << frame << TH; //Add in the frame size lastGeom.moveTop(lastGeom.y()-frame-TH); lastGeom.setHeight(lastGeom.height()+(2*frame)+TH); lastGeom.moveLeft(lastGeom.x()-frame); lastGeom.setWidth( lastGeom.width()+(2*frame)); + QList<unsigned int> margins; + margins << frame << frame << frame+TH << frame; //L/R/Top/Bottom qDebug() << " - With Frame:" << lastGeom; //Now adjust for a out-of-bounds location if(lastGeom.x() < 0){ lastGeom.moveLeft(0); } if(lastGeom.y() < 0){ lastGeom.moveTop(0); } qDebug() << " - Adjusted:" << lastGeom; this->setGeometry(lastGeom); + LWM::SYSTEM->WM_Set_Frame_Extents(CID, margins); } -void LWindow::SyncText(){ +void LWindowFrame::SyncText(){ QString txt = WIN->title(); if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowName(CID); } if(txt.isEmpty()){ txt = LWM::SYSTEM->OldWindowName(CID); } if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowVisibleName(CID); } if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowIconName(CID); } if(txt.isEmpty()){ txt = LWM::SYSTEM->WindowVisibleIconName(CID); } + if(txt.isEmpty()){ txt = LWM::SYSTEM->WM_ICCCM_GetClass(CID); } title->setText(txt); } // SIMPLE ANIMATIONS -void LWindow::showAnimation(LWM::WindowAction act){ - bool useanimation = true; //placeholder for the actual setting check +void LWindowFrame::showAnimation(LWM::WindowAction act){ + bool useanimation = (act!=lastAction); + if(anim->state()==QAbstractAnimation::Running){ + qDebug() << "New Animation Event:" << act; + return; + } //Setup the animation routine if(act==LWM::Show){ if(useanimation){ @@ -232,10 +236,13 @@ void LWindow::showAnimation(LWM::WindowAction act){ //anim->setStartValue( 0.0 ); //anim->setEndValue( 1.0 ); }else{ + if(this->layout()->count() <2){ this->layout()->addWidget(WinWidget); } + this->raise(); this->show(); //just show it right away } }else if(act==LWM::Hide){ + if(this->layout()->count() >1){ this->layout()->removeWidget(WinWidget); } if(useanimation){ //Collapse in on center point lastGeom = this->geometry(); @@ -248,8 +255,7 @@ void LWindow::showAnimation(LWM::WindowAction act){ }else if(act==LWM::Closed){ //Need to clean up the container widget first to prevent XCB errors //qDebug() << "Window Closed:" << WIN->winId() << CID; - //WIN->destroy(); //clean up any data - if(this->layout()->count()>1){ delete this->layout()->takeAt(1); } + if(this->layout()->count() >1){ this->layout()->removeWidget(WinWidget); } if(useanimation){ //Collapse in on center line lastGeom = this->geometry(); @@ -257,21 +263,42 @@ void LWindow::showAnimation(LWM::WindowAction act){ anim->setStartValue( QRect(this->geometry()) ); anim->setEndValue( QRect(this->geometry().x(), this->geometry().center().y(), this->width(), 0 ) ); }else{ - this->close(); //just hide it right away + CloseAll(); //just hide it right away } } if(useanimation){ + if(this->layout()->count() >1){ this->layout()->removeWidget(WinWidget); } this->show(); + //if(WIN!=0){ LWM::SYSTEM->WM_HideWindow(CID); } + qDebug() << " - Starting Animation:" << act; + lastAction = act; anim->start(); - //Also set any final values - if(act==LWM::Hide){ QTimer::singleShot(ANIMTIME, this, SLOT(hide()) ); } - if(act==LWM::Closed){ QTimer::singleShot(ANIMTIME, this, SLOT(close()) ); } }; } + +void LWindowFrame::finishedAnimation(){ + //Also set any final values + qDebug() << " - Finished Animation:" << lastAction; + switch(lastAction){ + case LWM::Show: + if(WIN!=0 && !Closing){ LWM::SYSTEM->WM_ShowWindow(CID); } + if(this->layout()->count()<2){ this->layout()->addWidget(WinWidget); } + break; + case LWM::Closed: + case LWM::Hide: + this->hide(); + default: + break; + } + if(Closing){ + emit Finished(); + } +} + // ================= // PUBLIC SLOTS // ================= -void LWindow::updateAppearance(){ +void LWindowFrame::updateAppearance(){ //Reload any button icons and such minB->setIcon(LXDG::findIcon("window-suppressed","")); maxB->setIcon(LXDG::findIcon("view-fullscreen","")); @@ -279,37 +306,44 @@ void LWindow::updateAppearance(){ otherB->setIcon(LXDG::findIcon("configure","")); } -void LWindow::windowChanged(LWM::WindowAction act){ +void LWindowFrame::windowChanged(LWM::WindowAction act){ //A window property was changed - update accordingly switch(act){ + case LWM::Closed: + /*if(anim->state()==QAbstractAnimation::Running){ + anim->pause(); + //delete WinWidget; + WIN = 0; + anim->resume(); + }*/ + Closing = true; case LWM::Hide: case LWM::Show: - case LWM::Closed: showAnimation(act); break; case LWM::MoveResize: //Re-adjust to the new position/size of the window - + SyncSize(true); break; + default: + break; //do nothing } } // ================= // PRIVATE SLOTS // ================= -void LWindow::closeClicked(){ - qDebug() << "Closing Window"; +void LWindowFrame::closeClicked(){ + qDebug() << "Closing Window" << LWM::SYSTEM->WM_ICCCM_GetClass(CID); //First try the close event to let the client app do cleanup/etc - WIN->hide(); LWM::SYSTEM->WM_CloseWindow(CID); - showAnimation(LWM::Closed); //temporary testing line - should be run after destroy event automatically later } -void LWindow::minClicked(){ +void LWindowFrame::minClicked(){ qDebug() << "Minimize Window"; this->showMinimized(); } -void LWindow::maxClicked(){ +void LWindowFrame::maxClicked(){ if(normalGeom.isNull()){ qDebug() << "Maximize Window"; normalGeom = this->geometry(); //save for later @@ -322,17 +356,23 @@ void LWindow::maxClicked(){ } } -void LWindow::otherClicked(QAction* act){ +void LWindowFrame::otherClicked(QAction* act){ QString action = act->whatsThis(); } +void LWindowFrame::CloseAll(){ + qDebug() << " - Closing Frame"; + this->hide(); + emit Finished(); +} // ===================== // PROTECTED // ===================== -void LWindow::mousePressEvent(QMouseEvent *ev){ - qDebug() << "Mouse Press Event"; +void LWindowFrame::mousePressEvent(QMouseEvent *ev){ + qDebug() << "Frame Mouse Press Event"; offset.setX(0); offset.setY(0); if(activeState != Normal){ return; } // do nothing - already in a state of grabbed mouse + this->activateWindow(); if(this->childAt(ev->pos())!=0){ //Check for any non-left-click event and skip it if(ev->button()!=Qt::LeftButton){ return; } @@ -346,7 +386,7 @@ void LWindow::mousePressEvent(QMouseEvent *ev){ } -void LWindow::mouseMoveEvent(QMouseEvent *ev){ +void LWindowFrame::mouseMoveEvent(QMouseEvent *ev){ ev->accept(); if(activeState == Normal){ setMouseCursor( getStateAtPoint(ev->pos()) ); //just update the mouse cursor @@ -381,14 +421,17 @@ void LWindow::mouseMoveEvent(QMouseEvent *ev){ break; case ResizeTopLeft: geom.setTopLeft(ev->globalPos()-offset); - break; + break; + default: + break; } this->setGeometry(geom); } } -void LWindow::mouseReleaseEvent(QMouseEvent *ev){ +void LWindowFrame::mouseReleaseEvent(QMouseEvent *ev){ //Check for a right-click event + qDebug() << "Frame Mouse Release Event"; ev->accept(); if( (activeState==Normal) && (this->childAt(ev->pos())==titleBar) && (ev->button()==Qt::RightButton) ){ otherM->popup(ev->globalPos()); diff --git a/lumina-wm-INCOMPLETE/LWindow.h b/lumina-wm-INCOMPLETE/LWindow.h index 61345736..10b0dd84 100644 --- a/lumina-wm-INCOMPLETE/LWindow.h +++ b/lumina-wm-INCOMPLETE/LWindow.h @@ -9,14 +9,11 @@ #include "GlobalDefines.h" -class LWindow : public QFrame{ +class LWindowFrame : public QFrame{ Q_OBJECT public: - LWindow(WId client); //MUST have a valid client window - ~LWindow(); - - WId clientID(); - bool hasFrame(); + LWindowFrame(WId client, QWidget *parent = 0); //MUST have a valid client window + ~LWindowFrame(); private: void InitWindow(); //Initialize all the internal widgets @@ -32,8 +29,11 @@ private: //General Properties/Modifications WId CID; //Client ID QWindow *WIN; //Embedded window container + QWidget *WinWidget; + bool Closing; + LWM::WindowAction lastAction; //QBackingStore *WINBACK; - void SyncSize(); //sync the window/frame geometries + void SyncSize(bool fromwin = false); //sync the window/frame geometries void SyncText(); //Window Frame Widgets/Items @@ -45,7 +45,8 @@ private: //Animations QPropertyAnimation *anim; //used for appear/disappear animations QRect lastGeom; //used for appear/disappear animations - void showAnimation(LWM::WindowAction); + void showAnimation(LWM::WindowAction); //sets lastAction + public slots: //These slots are generally used for the outside event watcher to prod for changes @@ -53,19 +54,55 @@ public slots: void windowChanged(LWM::WindowAction); private slots: + void finishedAnimation(); //uses lastAction void closeClicked(); void minClicked(); void maxClicked(); void otherClicked(QAction*); + void CloseAll(); + protected: void mousePressEvent(QMouseEvent*); void mouseMoveEvent(QMouseEvent*); void mouseReleaseEvent(QMouseEvent*); signals: + void Finished(); //This means the window is completely finished (with animations and such) and should be removed from any lists + +}; +class LWindow : public QObject{ + Q_OBJECT +signals: + void Finished(WId client); //ready to be removed +private: + WId CID; + LWindowFrame *FID; +private slots: + void frameclosed(){ + qDebug() << " - Window got frame closed signal"; + FID->close(); + delete FID; + emit Finished(CID); + } +public: + LWindow(WId client){ + FID= 0; + CID = client; + QList<LXCB::WINDOWTYPE> list = LWM::SYSTEM->WM_Get_Window_Type(CID); + if(list.isEmpty() || (list.first()==LXCB::T_DIALOG || list.first()==LXCB::T_NORMAL) ){ + FID = new LWindowFrame(CID); + connect(FID, SIGNAL(Finished()), this, SLOT(frameclosed()) ); + } + } + ~LWindow(){ + if(FID!=0){delete FID;} + } + + WId clientID(){ return CID; } + bool hasFrame(){ return FID!=0; } + LWindowFrame* frame(){ return FID; } }; - #endif
\ No newline at end of file diff --git a/lumina-wm-INCOMPLETE/LWindowManager.cpp b/lumina-wm-INCOMPLETE/LWindowManager.cpp new file mode 100644 index 00000000..87519ff6 --- /dev/null +++ b/lumina-wm-INCOMPLETE/LWindowManager.cpp @@ -0,0 +1,155 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2015, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "LWindowManager.h" + +#define DEBUG 1 + +LWindowManager::LWindowManager(){ + +} + +LWindowManager::~LWindowManager(){ + +} + +bool LWindowManager::start(){ + //Should probably do a quick loop over any existing windows with the root as parent (just in case) + QList<WId> initial = LWM::SYSTEM->WM_RootWindows(); + for(int i=0; i<initial.length(); i++){ + NewWindow(initial[i], false); //These ones did not explicitly request to be mapped + } + RestackWindows(); + return true; +} + +void LWindowManager::stop(){ + for(int i=0; i<WINS.length(); i++){ + if(WINS[i]->hasFrame()){ + LWM::SYSTEM->UnembedWindow(WINS[i]->clientID()); + WINS[i]->frame()->close(); + } + } +} +//=============== +// PUBLIC SLOTS +//=============== +void LWindowManager::NewWindow(WId win, bool requested){ + //Verify that this window can/should be managed first + //if(DEBUG){ qDebug() << "New Window:" << LWM::SYSTEM->WM_ICCCM_GetClass(win); } + QString wclass = LWM::SYSTEM->WM_ICCCM_GetClass(win); + if( wclass.contains("lumina-wm",Qt::CaseInsensitive) ){ return; } //just in case: prevent recursion + else{ + bool ok = (wclass.isEmpty() ? false : LWM::SYSTEM->WM_ManageWindow(win, requested) ); + if(!ok){ + //See if this window is just a transient pointing to some other window + WId tran = LWM::SYSTEM->WM_ICCCM_GetTransientFor(win); + if(tran!=win && tran!=0){ + win = tran; + ok = LWM::SYSTEM->WM_ManageWindow(win); + } + } + if(!ok){ return; } + } + if(DEBUG){ qDebug() << "New Managed Window:" << LWM::SYSTEM->WM_ICCCM_GetClass(win); } + LWindow *lwin = new LWindow(win); + connect(lwin, SIGNAL(Finished(WId)), this, SLOT(FinishedWindow(WId)) ); + WINS << lwin; + if(lwin->hasFrame()){ + lwin->frame()->windowChanged(LWM::Show); //Make sure to show it right away + }else{ + LWM::SYSTEM->WM_ShowWindow(win); //just map the window right now + } +} + +void LWindowManager::ClosedWindow(WId win){ + for(int i=0; i<WINS.length(); i++){ + if(WINS[i]->clientID()==win){ + qDebug() << " - Closed Window"; + if(WINS[i]->hasFrame()){ WINS[i]->frame()->windowChanged(LWM::Closed); } + else{ + FinishedWindow(win); + } + break; + } + } +} + +void LWindowManager::ModifyWindow(WId win, LWM::WindowAction act){ + for(int i=0; i<WINS.length(); i++){ + if(WINS[i]->clientID()==win){ + if(WINS[i]->hasFrame()){ WINS[i]->frame()->windowChanged(act); } + return; + } + } + //If it gets this far - it is an unmanaged window + if(act==LWM::Show){ + NewWindow(win); + } + RestackWindows(); +} + +void LWindowManager::RestackWindows(){ + Stack_Desktop.clear(); Stack_Below.clear(); Stack_Normal.clear(); Stack_Above.clear(); Stack_Fullscreen.clear(); + QList<WId> currwins; + int cwork = LWM::SYSTEM->WM_Get_Current_Desktop(); + int winwork = -1; + QList<LXCB::WINDOWSTATE> states; + QList<LXCB::WINDOWTYPE> types; + for(int i=0; i<WINS.length(); i++){ + //Only show windows on the current desktop + winwork = LWM::SYSTEM->WM_Get_Desktop(WINS[i]->clientID()); + states = LWM::SYSTEM->WM_Get_Window_States(WINS[i]->clientID()); + types = LWM::SYSTEM->WM_Get_Window_Type(WINS[i]->clientID()); + WId id = WINS[i]->clientID(); + if(WINS[i]->hasFrame()){ id = WINS[i]->frame()->winId(); } + if(winwork<0 || winwork == cwork || states.contains(LXCB::S_STICKY) ){ + //Now check the state/type and put it in the proper stack + currwins << WINS[i]->clientID(); //add this to the overall "age" list + //Now add it to the proper stack + if(types.contains(LXCB::T_DESKTOP)){ Stack_Desktop << id; } + else if(states.contains(LXCB::S_BELOW)){ Stack_Below << id; } + else if(types.contains(LXCB::T_DOCK) || states.contains(LXCB::S_ABOVE) ){ Stack_Above << id; } + else if(states.contains(LXCB::S_FULLSCREEN)){ Stack_Fullscreen << id; } + else{ Stack_Normal << id; } + } + } + //Now set the root properties for these lists + LWM::SYSTEM->WM_Set_Client_List(currwins, false); //age-ordered version + LWM::SYSTEM->WM_Set_Client_List(QList<WId>() << Stack_Desktop << Stack_Below << Stack_Normal << Stack_Above << Stack_Fullscreen, true); //stacking order version + //Now re-paint (in order) the windows + RepaintWindows(); +} + +void LWindowManager::RepaintWindows(){ + //Go through all the current windows (in stacking order) and re-paint them + for(int i=0; i<Stack_Desktop.length(); i++){ + LWM::SYSTEM->WM_ShowWindow(Stack_Desktop[i]); + } + for(int i=0; i<Stack_Below.length(); i++){ + LWM::SYSTEM->WM_ShowWindow(Stack_Below[i]); + } + for(int i=0; i<Stack_Normal.length(); i++){ + LWM::SYSTEM->WM_ShowWindow(Stack_Normal[i]); + } + for(int i=0; i<Stack_Above.length(); i++){ + LWM::SYSTEM->WM_ShowWindow(Stack_Above[i]); + } + for(int i=0; i<Stack_Fullscreen.length(); i++){ + LWM::SYSTEM->WM_ShowWindow(Stack_Fullscreen[i]); + } +} + +//================= +// PRIVATE SLOTS +//================= +void LWindowManager::FinishedWindow(WId win){ + for(int i=0; i<WINS.length(); i++){ + if(WINS[i]->clientID() == win){ qDebug() << " - Finished Window"; delete WINS.takeAt(i); break; } + } + //Now update the list of clients + RestackWindows(); +} diff --git a/lumina-wm-INCOMPLETE/LWindowManager.h b/lumina-wm-INCOMPLETE/LWindowManager.h new file mode 100644 index 00000000..203efa1b --- /dev/null +++ b/lumina-wm-INCOMPLETE/LWindowManager.h @@ -0,0 +1,40 @@ +//=========================================== +// 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_WINDOW_MANAGER_MAIN_CLASS_H +#define _LUMINA_DESKTOP_WINDOW_MANAGER_MAIN_CLASS_H + +#include "GlobalDefines.h" +#include "LWindow.h" + +class LWindowManager : public QObject{ + Q_OBJECT +public: + LWindowManager(); + ~LWindowManager(); + + bool start(); + void stop(); + +private: + QList<LWindow*> WINS; + QList<WId> Stack_Desktop, Stack_Below, Stack_Normal, Stack_Above, Stack_Fullscreen; +public slots: + void NewWindow(WId win, bool requested = true); + void ClosedWindow(WId win); + void ModifyWindow(WId win, LWM::WindowAction act); + + void RestackWindows(); + void RepaintWindows(); + +private slots: + void FinishedWindow(WId win); //This is used for LWindow connections/animations + +signals: + void NewFullScreenWindows(QList<WId>); +}; + +#endif diff --git a/lumina-wm-INCOMPLETE/LXcbEventFilter.cpp b/lumina-wm-INCOMPLETE/LXcbEventFilter.cpp index ba825b90..6d6cef55 100644 --- a/lumina-wm-INCOMPLETE/LXcbEventFilter.cpp +++ b/lumina-wm-INCOMPLETE/LXcbEventFilter.cpp @@ -30,20 +30,23 @@ EventFilter::EventFilter() : QObject(){ EF = new XCBEventFilter(this); L_XCB::root_screen = xcb_aux_get_screen(QX11Info::connection(), QX11Info::appScreen()); L_XCB::root = L_XCB::root_screen->root; + SSLocked = false; + WMFlag = 0; } void EventFilter::start(){ if(DEBUG){ qDebug() << " - Install event filter..."; } QCoreApplication::instance()->installNativeEventFilter(EF); if(DEBUG){ qDebug() << " - Run request check..."; } - xcb_generic_error_t *status = xcb_request_check( QX11Info::connection(), xcb_change_window_attributes_checked(QX11Info::connection(), L_XCB::root, XCB_CW_EVENT_MASK, (uint32_t[]){ROOT_EVENT_MASK} ) ); - if(status){ + if(!LWM::SYSTEM->setupEventsForRoot()){ qCritical() << "[ERROR] Unable to setup WM event retrieval. Is another WM running?"; exit(1); } - //xcb_screensaver_select_input(QX11Info::connection(),QX11Info::appRootWindow() , masks); - xcb_flush(QX11Info::connection()); - + if(DEBUG){ qDebug() << " - Create WM ID Window"; } + WMFlag = LWM::SYSTEM->WM_CreateWindow(); + LWM::SYSTEM->setupEventsForRoot(WMFlag); + LWM::SYSTEM->WM_Set_Supporting_WM(WMFlag); + QCoreApplication::instance()->flush(); } //Constructor for the XCB event filter @@ -64,96 +67,138 @@ bool XCBEventFilter::nativeEventFilter(const QByteArray &eventType, void *messag //Now parse the event and emit signals as necessary switch( ev->response_type & ~0x80){ //============================== +// INTERACTIVITY EVENTS +//============================== case XCB_KEY_PRESS: - qDebug() << "Key Press Event"; + //This is a keyboard key press + //qDebug() << "Key Press Event"; obj->emit NewInputEvent(); + stopevent = BlockInputEvent( ((xcb_key_press_event_t *) ev)->root ); //use the main "root" window - not the child widget break; case XCB_KEY_RELEASE: - qDebug() << "Key Release Event"; + //This is a keyboard key release + //qDebug() << "Key Release Event"; obj->emit NewInputEvent(); + stopevent = BlockInputEvent( ((xcb_key_release_event_t *) ev)->root ); //use the main "root" window - not the child widget break; case XCB_BUTTON_PRESS: - qDebug() << "Button Press Event"; + //This is a mouse button press + //qDebug() << "Button Press Event"; obj->emit NewInputEvent(); + stopevent = BlockInputEvent( ((xcb_button_press_event_t *) ev)->root ); //use the main "root" window - not the child widget + if(!stopevent){ + //Activate the window right now if needed + if(LWM::SYSTEM->WM_Get_Active_Window()!=((xcb_button_press_event_t *) ev)->root){ + LWM::SYSTEM->WM_Set_Active_Window( ((xcb_button_press_event_t *) ev)->root); + } + } break; case XCB_BUTTON_RELEASE: - qDebug() << "Button Release Event"; - obj->emit NewInputEvent(); + //This is a mouse button release + //qDebug() << "Button Release Event"; + //xcb_button_release_event_t *tmp = (xcb_button_release_event_t *)ev; + stopevent = BlockInputEvent( ((xcb_button_release_event_t *) ev)->root ); //use the main "root" window - not the child widget break; case XCB_MOTION_NOTIFY: - qDebug() << "Motion Notify Event"; + //This is a mouse movement event + //qDebug() << "Motion Notify Event"; + obj->emit NewInputEvent(); + stopevent = BlockInputEvent( ((xcb_motion_notify_event_t *) ev)->root ); //use the main "root" window - not the child widget); + break; + case XCB_ENTER_NOTIFY: + //This is a mouse movement event when mouse goes over a new window + //qDebug() << "Enter Notify Event"; + obj->emit NewInputEvent(); + stopevent = BlockInputEvent( ((xcb_enter_notify_event_t *) ev)->root ); + break; + case XCB_LEAVE_NOTIFY: + //This is a mouse movement event when mouse goes leaves a window + //qDebug() << "Leave Notify Event"; obj->emit NewInputEvent(); + stopevent = BlockInputEvent(); break; //============================== - case XCB_PROPERTY_NOTIFY: - qDebug() << "Property Notify Event:"; - //qDebug() << " - Root Window:" << QX11Info::appRootWindow(); + case XCB_EXPOSE: + //qDebug() << "Expose Notify Event:"; //qDebug() << " - Given Window:" << ((xcb_property_notify_event_t*)ev)->window; - //System-specific proprty change - if( SysNotifyAtoms.contains( ((xcb_property_notify_event_t*)ev)->atom ) ){ - //Update the status/list of all running windows - //session->WindowPropertyEvent(); - - //window-specific property change - }else if( WinNotifyAtoms.contains( ((xcb_property_notify_event_t*)ev)->atom ) ){ - //Ping only that window - //session->WindowPropertyEvent( ((xcb_property_notify_event_t*)ev)->window ); - //session->WindowPropertyEvent(); - } + break; +//============================== + case XCB_MAP_NOTIFY: + 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, LWM::Show); break; //============================== - case XCB_CLIENT_MESSAGE: - qDebug() << "Client Message Event"; - //qDebug() << " - Root Window:" << QX11Info::appRootWindow(); - //qDebug() << " - Given Window:" << ((xcb_client_message_event_t*)ev)->window; - //if( TrayDmgFlag!=0 && ((xcb_client_message_event_t*)ev)->type == _NET_SYSTEM_TRAY_OPCODE && ((xcb_client_message_event_t*)ev)->format == 32){ - //data32[0] is timestamp, [1] is opcode, [2] is window handle - //if(SYSTEM_TRAY_REQUEST_DOCK == ((xcb_client_message_event_t*)ev)->data.data32[1]){ - //session->SysTrayDockRequest( ((xcb_client_message_event_t*)ev)->data.data32[2] ); - //} - //Ignore the System Tray messages at the moment (let the WM handle it) - - //window-specific property changes - /*}else if( ((xcb_client_message_event_t*)ev)->type == session->XCB->EWMH._NET_WM_STATE ){ - if( session->XCB->WindowIsMaximized( ((xcb_client_message_event_t*)ev)->window ) ){ - //Quick fix for maximized windows (since Fluxbox is not doing the STRUT detection properly) - session->adjustWindowGeom( ((xcb_client_message_event_t*)ev)->window ); - } - session->WindowPropertyEvent( ((xcb_client_message_event_t*)ev)->window );*/ - //}else if( WinNotifyAtoms.contains( ((xcb_client_message_event_t*)ev)->type ) ){ - //Ping only that window - //session->WindowPropertyEvent( ((xcb_client_message_event_t*)ev)->window ); - //session->WindowPropertyEvent(); - //} + case XCB_CREATE_NOTIFY: + qDebug() << "Window Create Event"; break; +//============================== + case XCB_UNMAP_NOTIFY: + qDebug() << "Window Unmap Event"; + obj->emit ModifyWindow( ((xcb_unmap_notify_event_t *)ev)->window, LWM::Hide); + break; //============================== case XCB_DESTROY_NOTIFY: qDebug() << "Window Closed Event"; - //session->WindowClosedEvent( ( (xcb_destroy_notify_event_t*)ev )->window ); + obj->emit WindowClosed( ((xcb_destroy_notify_event_t *) ev)->window ); + break; +//============================== + case XCB_FOCUS_IN: + //qDebug() << "Focus In Event:"; + break; +//============================== + case XCB_FOCUS_OUT: + //qDebug() << "Focus Out Event:"; + break; +//============================== + case XCB_PROPERTY_NOTIFY: + //qDebug() << "Property Notify Event:"; + //qDebug() << " - Given Window:" << ((xcb_property_notify_event_t*)ev)->window; + break; +//============================== + case XCB_CLIENT_MESSAGE: + //qDebug() << "Client Message Event"; + //qDebug() << " - Given Window:" << ((xcb_client_message_event_t*)ev)->window; break; //============================== case XCB_CONFIGURE_NOTIFY: - qDebug() << "Configure Notify Event"; - //session->WindowConfigureEvent( ((xcb_configure_notify_event_t*)ev)->window ); + //qDebug() << "Configure Notify Event"; + break; +//============================== + case XCB_CONFIGURE_REQUEST: + //qDebug() << "Configure Request Event"; break; //============================== case XCB_SELECTION_CLEAR: - qDebug() << "Selection Clear Event"; - //session->WindowSelectionClearEvent( ((xcb_selection_clear_event_t*)ev)->owner ); + //qDebug() << "Selection Clear Event"; break; //============================== + case 85: //not sure what event this is - but it seems to come up very often (just hide the notice) + case 0: + case XCB_GE_GENERIC: + break; //generic event - don't do anything special default: - //if(TrayDmgFlag!=0){ - //if( (ev->response_type & ~0x80)==TrayDmgFlag){ - //session->WindowDamageEvent( ((xcb_damage_notify_event_t*)ev)->drawable ); - //} - //} - //else{ - qDebug() << "Default Event:" << (ev->response_type & ~0x80); - //} + qDebug() << "Default Event:" << (ev->response_type & ~0x80); //============================== } } - //qDebug() << " - finished event"; return stopevent; } + +bool XCBEventFilter::BlockInputEvent(WId win){ + //Checks the current state of the WM and sets the stop flag as needed + // - Always let the screensaver know about the event first (need to reset timers and such) + obj->emit NewInputEvent(); + // - Check the state of the screensaver + + if(obj->SSLocked){ qDebug() << "SS Locked"; return true; } + // - Check the state of any fullscreen apps + else if( win!=0 && !obj->FS_WINS.isEmpty()){ + if(!obj->FS_WINS.contains(win) ){ + //If this event is for an app underneath a fullscreen window - stop it + if(obj->FS_WINS.length() == QApplication::desktop()->screenCount()){ qDebug() << "Screens Covered"; return true; } //all screens covered right now + } + } + return false; +} diff --git a/lumina-wm-INCOMPLETE/LXcbEventFilter.h b/lumina-wm-INCOMPLETE/LXcbEventFilter.h index 86e77939..28bab024 100644 --- a/lumina-wm-INCOMPLETE/LXcbEventFilter.h +++ b/lumina-wm-INCOMPLETE/LXcbEventFilter.h @@ -46,46 +46,33 @@ XCB_CLIENT_MESSAGE //#define SYSTEM_TRAY_BEGIN_MESSAGE 1 //#define SYSTEM_TRAY_CANCEL_MESSAGE 2 - -// --------------------------------------------- -// Lifted these mask definitions from the i3 window manager (BSD Licensed as well) 5/14/15 - Ken Moore -#define CHILD_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | \ - XCB_EVENT_MASK_FOCUS_CHANGE) - -/** The XCB_CW_EVENT_MASK for its frame */ -#define FRAME_EVENT_MASK (XCB_EVENT_MASK_BUTTON_PRESS | /* ...mouse is pressed/released */ \ - XCB_EVENT_MASK_BUTTON_RELEASE | \ - XCB_EVENT_MASK_POINTER_MOTION | /* ...mouse is moved */ \ - XCB_EVENT_MASK_EXPOSURE | /* ...our window needs to be redrawn */ \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | /* ...the frame gets destroyed */ \ - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | /* ...the application tries to resize itself */ \ - XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | /* ...subwindows get notifies */ \ - XCB_EVENT_MASK_ENTER_WINDOW) /* ...user moves cursor inside our window */ - -#define ROOT_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \ - XCB_EVENT_MASK_BUTTON_PRESS | \ - XCB_EVENT_MASK_STRUCTURE_NOTIFY | /* when the user adds a screen (e.g. video \ - projector), the root window gets a \ - ConfigureNotify */ \ - XCB_EVENT_MASK_POINTER_MOTION | \ - XCB_EVENT_MASK_PROPERTY_CHANGE | \ - XCB_EVENT_MASK_ENTER_WINDOW) -// --------------------------------------------- - class EventFilter : public QObject{ Q_OBJECT private: QAbstractNativeEventFilter* EF; + WId WMFlag; //used to flag a running WM process + public: EventFilter(); ~EventFilter(){} void start(); + //Public variables for the event filter to use/check + QList<WId> FS_WINS; //Full-screen windows (1 per monitor) - used for hiding non-app events as needed + bool SSLocked; + +public slots: + void StartedSS(){ SSLocked = true; } + void StoppedSS(){ SSLocked = false; } + void FullScreenChanged(QList<WId> fslist){ FS_WINS = fslist; } + signals: void NewInputEvent(); + void NewManagedWindow(WId); + void WindowClosed(WId); + void ModifyWindow(WId win, LWM::WindowAction); }; class XCBEventFilter : public QAbstractNativeEventFilter{ @@ -97,7 +84,6 @@ public: virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE; private: - //LXCB *XCB; EventFilter *obj; QList<xcb_atom_t> WinNotifyAtoms, SysNotifyAtoms; @@ -123,7 +109,9 @@ private: } - //Event handling functions (return true if event accepted/blocked) + bool BlockInputEvent(WId win = 0); //Checks the current state of the WM and sets the stop flag as needed + + //Longer Event handling functions //bool ParseKeyPressEvent(); //bool ParseKeyReleaseEvent(); //bool ParseButtonPressEvent(); diff --git a/lumina-wm-INCOMPLETE/WMSession.cpp b/lumina-wm-INCOMPLETE/WMSession.cpp index bed31ed9..4a7c6e02 100644 --- a/lumina-wm-INCOMPLETE/WMSession.cpp +++ b/lumina-wm-INCOMPLETE/WMSession.cpp @@ -15,9 +15,18 @@ WMSession::WMSession(){ EFILTER = new EventFilter(); if(DEBUG){ qDebug() << "Creating Screen Saver..."; } SS = new LScreenSaver(); - + if(DEBUG){ qDebug() << "Creating Window Manager..."; } + WM = new LWindowManager(); + EVThread = new QThread(); + EFILTER->moveToThread(EVThread); //Setup connections connect(EFILTER, SIGNAL(NewInputEvent()), SS, SLOT(newInputEvent()) ); + connect(EFILTER, SIGNAL(NewManagedWindow(WId)), WM, SLOT(NewWindow(WId)) ); + connect(EFILTER, SIGNAL(WindowClosed(WId)), WM, SLOT(ClosedWindow(WId)) ); + connect(EFILTER, SIGNAL(ModifyWindow(WId, LWM::WindowAction)), WM, SLOT(ModifyWindow(WId,LWM::WindowAction)) ); + connect(SS, SIGNAL(StartingScreenSaver()), EFILTER, SLOT(StartedSS()) ); + connect(SS, SIGNAL(ClosingScreenSaver()), EFILTER, SLOT(StoppedSS()) ); + connect(WM, SIGNAL(NewFullScreenWindows(QList<WId>)), EFILTER, SLOT(FullScreenChanged(QList<WId>)) ); } WMSession::~WMSession(){ @@ -29,7 +38,10 @@ void WMSession::start(bool SSONLY){ SS->start(); if(SSONLY){ return; } //Now start pulling/filtering events + if(DEBUG){ qDebug() << "Starting Window Manager..."; } + WM->start(); if(DEBUG){ qDebug() << "Starting Event Filter..."; } + EVThread->start(); EFILTER->start(); if(DEBUG){ qDebug() << "Done Starting WM session..."; } } diff --git a/lumina-wm-INCOMPLETE/WMSession.h b/lumina-wm-INCOMPLETE/WMSession.h index 575a61e7..5b511326 100644 --- a/lumina-wm-INCOMPLETE/WMSession.h +++ b/lumina-wm-INCOMPLETE/WMSession.h @@ -11,6 +11,7 @@ #include "LScreenSaver.h" #include "LXcbEventFilter.h" +#include "LWindowManager.h" class WMSession : public QObject{ Q_OBJECT @@ -25,9 +26,10 @@ private: EventFilter *EFILTER; //ScreenSaver LScreenSaver *SS; - //Window Manager - + LWindowManager *WM; + + QThread *EVThread; //X Event thread public slots: void reloadIcons(); diff --git a/lumina-wm-INCOMPLETE/lumina-wm.pro b/lumina-wm-INCOMPLETE/lumina-wm.pro index 7e2c0c82..aba210fe 100644 --- a/lumina-wm-INCOMPLETE/lumina-wm.pro +++ b/lumina-wm-INCOMPLETE/lumina-wm.pro @@ -31,7 +31,8 @@ SOURCES += main.cpp \ SSBaseWidget.cpp \ LLockScreen.cpp \ LXcbEventFilter.cpp \ - LWindow.cpp + LWindow.cpp \ + LWindowManager.cpp HEADERS += GlobalDefines.h \ @@ -40,7 +41,8 @@ HEADERS += GlobalDefines.h \ SSBaseWidget.h \ LLockScreen.h \ LXcbEventFilter.h \ - LWindow.h + LWindow.h \ + LWindowManager.h FORMS += LLockScreen.ui diff --git a/lumina-wm-INCOMPLETE/main.cpp b/lumina-wm-INCOMPLETE/main.cpp index 9ac227c8..50251fa5 100644 --- a/lumina-wm-INCOMPLETE/main.cpp +++ b/lumina-wm-INCOMPLETE/main.cpp @@ -42,7 +42,7 @@ int main(int argc, char ** argv) qDebug() << " - Loading window frame..."; LWindow win(dlg.winId()); //have it wrap around the dialog qDebug() << " - Show frame..."; - win.windowChanged(LWM::Show); + win.frame()->windowChanged(LWM::Show); qDebug() << " - Start event loop..."; a.setQuitOnLastWindowClosed(true); return a.exec(); |