From 334bb3d2ebb26ea518c0f2c98490d79d6b3e77ef Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Thu, 20 Jul 2017 17:17:54 -0400 Subject: Get the compositing and window interactions all cleaned up. Seems to work great now. --- src-qt5/core/libLumina/DesktopSettings.cpp | 2 + src-qt5/core/libLumina/DesktopSettings.h | 2 +- src-qt5/core/libLumina/NativeEmbedWidget.cpp | 66 ++++++++++++++++------ src-qt5/core/libLumina/NativeEmbedWidget.h | 7 +++ .../core/libLumina/RootSubWindow-animations.cpp | 7 ++- src-qt5/core/libLumina/RootSubWindow.cpp | 28 +++------ src-qt5/core/libLumina/RootWindow.cpp | 10 ++-- 7 files changed, 77 insertions(+), 45 deletions(-) (limited to 'src-qt5/core') diff --git a/src-qt5/core/libLumina/DesktopSettings.cpp b/src-qt5/core/libLumina/DesktopSettings.cpp index 47dc29de..8bda1ac5 100644 --- a/src-qt5/core/libLumina/DesktopSettings.cpp +++ b/src-qt5/core/libLumina/DesktopSettings.cpp @@ -238,6 +238,8 @@ QString DesktopSettings::rel_path(DesktopSettings::File file){ name="keys"; break; case DesktopSettings::Theme: name="theme"; break; + case DesktopSettings::Animation: + name="animations"; break; } return FILEPREFIX+name+".conf"; } diff --git a/src-qt5/core/libLumina/DesktopSettings.h b/src-qt5/core/libLumina/DesktopSettings.h index 57a85791..dcb10bb6 100644 --- a/src-qt5/core/libLumina/DesktopSettings.h +++ b/src-qt5/core/libLumina/DesktopSettings.h @@ -25,7 +25,7 @@ class DesktopSettings : public QObject{ Q_OBJECT public: - enum File{ System, Favorites, Environment, Session, Desktop, ContextMenu, Keys, Theme }; + enum File{ System, Favorites, Environment, Session, Desktop, ContextMenu, Keys, Theme, Animation }; DesktopSettings(QObject *parent = 0); ~DesktopSettings(); diff --git a/src-qt5/core/libLumina/NativeEmbedWidget.cpp b/src-qt5/core/libLumina/NativeEmbedWidget.cpp index e3c19e9f..ebefa994 100644 --- a/src-qt5/core/libLumina/NativeEmbedWidget.cpp +++ b/src-qt5/core/libLumina/NativeEmbedWidget.cpp @@ -37,8 +37,8 @@ inline void registerClientEvents(WId id){ // ============ //Simplification functions for the XCB/XLib interactions void NativeEmbedWidget::syncWinSize(QSize sz){ - if(WIN==0){ return; } - if(!sz.isValid()){ sz = this->size(); } //use the current widget size + if(WIN==0 ){ return; } + else if(!sz.isValid()){ sz = this->size(); } //use the current widget size //qDebug() << "Sync Window Size:" << sz; if(sz == winSize){ return; } //no change const uint32_t valList[2] = {(uint32_t) sz.width(), (uint32_t) sz.height()}; @@ -58,9 +58,11 @@ void NativeEmbedWidget::hideWindow(){ void NativeEmbedWidget::showWindow(){ xcb_map_window(QX11Info::connection(), WIN->id()); + QTimer::singleShot(0,this, SLOT(repaintWindow())); } QImage NativeEmbedWidget::windowImage(QRect geom){ + //if(paused){ return QImage(); } //Pull the XCB pixmap out of the compositing layer xcb_pixmap_t pix = xcb_generate_id(QX11Info::connection()); xcb_composite_name_window_pixmap(QX11Info::connection(), WIN->id(), pix); @@ -85,7 +87,8 @@ QImage NativeEmbedWidget::windowImage(QRect geom){ // ============ NativeEmbedWidget::NativeEmbedWidget(QWidget *parent) : QWidget(parent){ WIN = 0; //nothing embedded yet - this->setSizeIncrement(2,2); + paused = false; + //this->setSizeIncrement(2,2); } bool NativeEmbedWidget::embedWindow(NativeWindow *window){ @@ -141,9 +144,23 @@ bool NativeEmbedWidget::isEmbedded(){ // ============== // PUBLIC SLOTS // ============== +//Pause/resume +void NativeEmbedWidget::pause(){ + if(winImage.isNull()){ repaintWindow(); } //make sure we have one image already cached first + paused = true; +} + +void NativeEmbedWidget::resume(){ + paused = false; + //syncWinSize(); + //showWindow(); + repaintWindow(); //update the cached image right away + this->parentWidget()->update(); +} + void NativeEmbedWidget::resyncWindow(){ if(WIN==0){ return; } - return; //skip the stuff below (not working) + /*return; //skip the stuff below (not working) QRect geom = WIN->geometry(); //Send an artificial configureNotify event to the window with the global position/size included xcb_configure_notify_event_t event; @@ -158,16 +175,25 @@ void NativeEmbedWidget::resyncWindow(){ event.event = WIN->id(); event.response_type = XCB_CONFIGURE_NOTIFY; xcb_send_event(QX11Info::connection(), false, WIN->id(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, (const char *) &event); - - xcb_flush(QX11Info::connection()); + */ + //Just jitter the window size by 1 pixel really quick so the window knows to update it's geometry + QSize sz = this->size(); + uint32_t valList[2] = {(uint32_t) sz.width()-1, (uint32_t) sz.height()}; + uint32_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; + xcb_configure_window(QX11Info::connection(), WIN->id(), mask, valList); + xcb_flush(QX11Info::connection()); + valList[0] = (uint32_t) sz.width(); + xcb_configure_window(QX11Info::connection(), WIN->id(), mask, valList); + xcb_flush(QX11Info::connection()); } void NativeEmbedWidget::repaintWindow(){ - //qDebug() << "Update Window Image"; - QImage tmp = windowImage( QRect(QPoint(0,0), this->size()) ); - if(!tmp.isNull()){ - winImage = tmp; - }//else{ qDebug() << "Got Null Image!!"; } + //qDebug() << "Update Window Image:" << !paused; + if(paused){ return; } + QImage tmp = windowImage( QRect(QPoint(0,0), this->size()) ); + if(!tmp.isNull()){ + winImage = tmp; + }//else{ qDebug() << "Got Null Image!!"; } this->update(); } // ============== @@ -191,18 +217,24 @@ void NativeEmbedWidget::hideEvent(QHideEvent *ev){ } void NativeEmbedWidget::paintEvent(QPaintEvent *ev){ - if(this->size()!=winSize){ return; } //do not paint here - waiting to re-sync the sizes - else if(WIN==0){ QWidget::paintEvent(ev); return; } - else if(this->size() != winImage.size()){ return; } + if(WIN==0){ QWidget::paintEvent(ev); return; } + else if( winImage.isNull() ){ /*QTimer::singleShot(0, this, SLOT(repaintWindow()) );*/ return; } + else if(paused){ return; } + //else if(this->size()!=winSize){ QTimer::singleShot(0,this, SLOT(syncWinSize())); return; } //do not paint here - waiting to re-sync the sizes + //else if(this->size() != winImage.size()){ QTimer::singleShot(0, this, SLOT(repaintWindow()) ); return; } //Need to paint the image from the window onto the widget as an overlay QRect geom = ev->rect(); //atomic updates geom.adjust(-10,-10,10,10); //add an additional few pixels in each direction to be painted geom = geom.intersected(QRect(0,0,this->width(), this->height())); //ensure intersection with actual window - if(!winImage.isNull()){ if( !QRect(QPoint(0,0),winImage.size()).contains(geom) ){ QTimer::singleShot(0,this, SLOT(repaintWindow()) );return; } QPainter P(this); - P.drawImage( geom , winImage, geom, Qt::NoOpaqueDetection); //1-to-1 mapping + P.setClipping(true); + P.setClipRect(0,0,this->width(), this->height()); + //qDebug() << "Paint Embed Window:" << geom << winImage.size(); + /*if(winImage.size().width() <= geom.size().width() && winImage.size().height() <= geom.size().height()){*/ P.drawImage( geom , winImage); //} + //else{ QImage scaled = winImage.scaled(geom.size()); P.drawImage(geom, scaled); } + //P.drawImage( geom , winImage, geom, Qt::NoOpaqueDetection); //1-to-1 mapping //Note: Qt::NoOpaqueDetection Speeds up the paint by bypassing the checks to see if there are [semi-]transparent pixels // Since this is an embedded image - we fully expect there to be transparency all/most of the time. - } + } diff --git a/src-qt5/core/libLumina/NativeEmbedWidget.h b/src-qt5/core/libLumina/NativeEmbedWidget.h index 756c8317..65e03c51 100644 --- a/src-qt5/core/libLumina/NativeEmbedWidget.h +++ b/src-qt5/core/libLumina/NativeEmbedWidget.h @@ -25,6 +25,7 @@ private: NativeWindow *WIN; QSize winSize; QImage winImage; + bool paused; private slots: //Simplification functions @@ -42,7 +43,13 @@ public: bool detachWindow(); bool isEmbedded(); //status of the embed + + public slots: + //Pause/resume + void pause(); + void resume(); + void resyncWindow(); void repaintWindow(); diff --git a/src-qt5/core/libLumina/RootSubWindow-animations.cpp b/src-qt5/core/libLumina/RootSubWindow-animations.cpp index e3deed3a..ac813e3a 100644 --- a/src-qt5/core/libLumina/RootSubWindow-animations.cpp +++ b/src-qt5/core/libLumina/RootSubWindow-animations.cpp @@ -64,6 +64,7 @@ void RootSubWindow::loadAnimation(QString name, NativeWindow::Property prop, QVa animResetProp = anim->startValue(); QTimer::singleShot(anim->duration(), this, SLOT(hide()) ); } + WinWidget->pause(); anim->start(); this->show(); } //end of Visibility animation @@ -80,10 +81,10 @@ void RootSubWindow::animFinished(){ //Also ensure that the proper geometry is saved to the window structure QRect curg = this->geometry(); QRect wing = WIN->geometry(); - qDebug() << " - After Animation Reset:" << curg << wing; + //qDebug() << " - After Animation Reset:" << curg << wing; if(curg!=wing){ QRect clientg = clientGlobalGeom(); - qDebug() << "Sub Window geometry:" << clientg; + //qDebug() << "Sub Window geometry:" << clientg; WIN->setProperties(QList< NativeWindow::Property>() << NativeWindow::Size << NativeWindow::GlobalPos, QList() << clientg.size() << clientg.topLeft() ); WinWidget->resyncWindow(); //also let the window know about the current geometry @@ -91,4 +92,6 @@ void RootSubWindow::animFinished(){ } } animResetProp = QVariant(); //clear the variable + WinWidget->resume(); + } diff --git a/src-qt5/core/libLumina/RootSubWindow.cpp b/src-qt5/core/libLumina/RootSubWindow.cpp index 55b6bd2e..46599003 100644 --- a/src-qt5/core/libLumina/RootSubWindow.cpp +++ b/src-qt5/core/libLumina/RootSubWindow.cpp @@ -14,6 +14,7 @@ #define WIN_BORDER 5 #include +#include // === PUBLIC === RootSubWindow::RootSubWindow(QWidget *root, NativeWindow *win) : QFrame(root){ @@ -304,6 +305,7 @@ void RootSubWindow::startMoving(){ activeState = Move; offset = this->mapFromGlobal(curpt); setMouseCursor(activeState, true); //this one is an override cursor + WinWidget->pause(); //Also need to capture the mouse this->grabMouse(); } @@ -320,25 +322,8 @@ void RootSubWindow::propertiesChanged(QList props, QList switch(props[i]){ case NativeWindow::Visible: //qDebug() << "Got Visibility Change:" << vals[i] << this->geometry() << WIN->geometry(); - loadAnimation( "random", NativeWindow::Visible, vals[i]); - /*if(vals[i].toBool()){ - if(lastGeom.isNull()){ animResetProp = this->geometry(); } - else{ animResetProp = lastGeom; } - anim->setPropertyName("geometry"); - anim->setStartValue( QRect(animResetProp.toRect().center(), QSize(0,0)) ); - anim->setEndValue(animResetProp); - this->setGeometry( anim->startValue().toRect() ); //ensure the window is the initial geom before it becomes visible - anim->start(); - this->show(); - }else{ - animResetProp = this->geometry(); //hide event - should already be the right geom - lastGeom = this->geometry(); - anim->setPropertyName("geometry"); - anim->setStartValue(this->geometry()); - anim->setEndValue( QRect(this->geometry().center(), QSize(0,0) ) ); - anim->start(); - QTimer::singleShot(anim->duration(), this, SLOT(hide()) ); - }*/ + if(vals[i].toBool()){ loadAnimation( DesktopSettings::instance()->value(DesktopSettings::Animation, "window/appear", "random").toString(), NativeWindow::Visible, vals[i]); } + else{ loadAnimation( DesktopSettings::instance()->value(DesktopSettings::Animation, "window/disappear", "random").toString(), NativeWindow::Visible, vals[i]); } break; case NativeWindow::Title: titleLabel->setText(vals[i].toString()); @@ -396,7 +381,7 @@ void RootSubWindow::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->activate(); + //this->activate(); if(this->childAt(ev->pos())!=0){ //Check for any non-left-click event and skip it if(ev->button()!=Qt::LeftButton){ return; } @@ -407,6 +392,7 @@ void RootSubWindow::mousePressEvent(QMouseEvent *ev){ activeState = getStateAtPoint(ev->pos(), true); //also have it set the offset variable } setMouseCursor(activeState, true); //this one is an override cursor + if(activeState!=Normal){WinWidget->pause(); } QFrame::mousePressEvent(ev); } @@ -500,6 +486,7 @@ void RootSubWindow::mouseReleaseEvent(QMouseEvent *ev){ otherM->popup(ev->globalPos()); return; } + if(activeState!=Normal){ WinWidget->resume(); } activeState = Normal; QApplication::restoreOverrideCursor(); setMouseCursor( getStateAtPoint(ev->pos()) ); @@ -519,5 +506,4 @@ void RootSubWindow::moveEvent(QMoveEvent *ev){ if(!closing && anim->state()!=QAbstractAnimation::Running){ moveTimer->start(); } - } diff --git a/src-qt5/core/libLumina/RootWindow.cpp b/src-qt5/core/libLumina/RootWindow.cpp index 31faaf50..fda9ca0f 100644 --- a/src-qt5/core/libLumina/RootWindow.cpp +++ b/src-qt5/core/libLumina/RootWindow.cpp @@ -169,7 +169,7 @@ void RootWindow::ChangeWallpaper(QString id, RootWindow::ScaleType scale, QStrin void RootWindow::NewWindow(NativeWindow *win){ RootSubWindow *subwin = 0; - qDebug() << "Got New Window:" << win->property(NativeWindow::Title); + //qDebug() << "Got New Window:" << win->property(NativeWindow::Title); for(int i=0; iid() == win->id()){ subwin = WINDOWS[i]; } } @@ -185,7 +185,7 @@ void RootWindow::NewWindow(NativeWindow *win){ void RootWindow::CloseWindow(WId win){ for(int i=0; iid() == win){ qDebug() << "Remove Window From Root List"; WINDOWS.takeAt(i)->clientClosed(); break; } + if(WINDOWS[i]->id() == win){ WINDOWS.takeAt(i)->clientClosed(); break; } } } @@ -196,10 +196,12 @@ void RootWindow::paintEvent(QPaintEvent *ev){ //qDebug() << "RootWindow: PaintEvent:" << ev->rect(); //<< QDateTime::currentDateTime()->toString(QDateTime::ShortDate); bool found = false; QPainter painter(this); + QRect geom = ev->rect(); + geom.adjust(-10,-10,10,10); //give it a few more pixels in each direction to repaint (noticing some issues in Qt 5.7.1) for(int i=0; irect()) ){ + if(WALLPAPERS[i].area.intersects(geom) ){ found = true; - QRect intersect = WALLPAPERS[i].area.intersected(ev->rect()); + QRect intersect = WALLPAPERS[i].area.intersected(geom); painter.drawPixmap( intersect, WALLPAPERS[i].wallpaper, intersect.translated(-WALLPAPERS[i].area.x(), -WALLPAPERS[i].area.y()) ); } } -- cgit