From ef7735a27d66660ae8775ca3fef0af7b15926a85 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Wed, 19 Jul 2017 15:34:05 -0400 Subject: Get the compositing working much smoother now. Only re-grab the X11 image when it changes, then store it for all paint events (including partial painting updates) - making things much faster to update on-demand. --- src-qt5/core/libLumina/NativeEmbedWidget.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'src-qt5/core/libLumina/NativeEmbedWidget.cpp') diff --git a/src-qt5/core/libLumina/NativeEmbedWidget.cpp b/src-qt5/core/libLumina/NativeEmbedWidget.cpp index 80c843e0..34501f2a 100644 --- a/src-qt5/core/libLumina/NativeEmbedWidget.cpp +++ b/src-qt5/core/libLumina/NativeEmbedWidget.cpp @@ -163,6 +163,11 @@ void NativeEmbedWidget::resyncWindow(){ } 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!!"; } this->update(); } // ============== @@ -186,23 +191,17 @@ void NativeEmbedWidget::hideEvent(QHideEvent *ev){ } void NativeEmbedWidget::paintEvent(QPaintEvent *ev){ - //QWidget::paintEvent(ev); //ensure all the Qt-compositing is done first if(this->size()!=winSize){ return; } //do not paint here - waiting to re-sync the sizes if(WIN==0){ QWidget::paintEvent(ev); return; } //Need to paint the image from the window onto the widget as an overlay - QRect geom = QRect(0,0,this->width(), this->height()); //always paint the whole window - //qDebug() << "Get Paint image:" << ev->rect() << geom; - //geom = ev->rect(); //atomic updates - //geom.adjust(-1,-1,1,1); //add an additional pixel in each direction to be painted - //geom = geom.intersected(QRect(0,0,this->width(), this->height())); //ensure intersection with actual window - QImage img = windowImage(geom); - if(!img.isNull()){ - if(img.size() != geom.size()){ return; } + QRect geom = ev->rect(); //atomic updates + geom.adjust(-1,-1,1,1); //add an additional pixel 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 , img, QRect(geom.topLeft(), img.size()), Qt::NoOpaqueDetection); //1-to-1 mapping - //qDebug() << "Painted Rect:" << ev->rect() << this->geometry(); + 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 most of the time. + // Since this is an embedded image - we fully expect there to be transparency all/most of the time. } - //qDebug() << "Done Painting"; } -- cgit From 23b870f04c46e8fa6d4ca2b14eb6d9ea2285a4c0 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Thu, 20 Jul 2017 12:40:16 -0400 Subject: Add a window animation framework, with 7 visibility animations for starters. --- src-qt5/core/libLumina/NativeEmbedWidget.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src-qt5/core/libLumina/NativeEmbedWidget.cpp') diff --git a/src-qt5/core/libLumina/NativeEmbedWidget.cpp b/src-qt5/core/libLumina/NativeEmbedWidget.cpp index 34501f2a..e3c19e9f 100644 --- a/src-qt5/core/libLumina/NativeEmbedWidget.cpp +++ b/src-qt5/core/libLumina/NativeEmbedWidget.cpp @@ -163,11 +163,11 @@ void NativeEmbedWidget::resyncWindow(){ } void NativeEmbedWidget::repaintWindow(){ - qDebug() << "Update Window Image"; + //qDebug() << "Update Window Image"; QImage tmp = windowImage( QRect(QPoint(0,0), this->size()) ); if(!tmp.isNull()){ winImage = tmp; - }else{ qDebug() << "Got Null Image!!"; } + }//else{ qDebug() << "Got Null Image!!"; } this->update(); } // ============== @@ -192,10 +192,11 @@ 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 - if(WIN==0){ QWidget::paintEvent(ev); return; } + else if(WIN==0){ QWidget::paintEvent(ev); return; } + else if(this->size() != winImage.size()){ return; } //Need to paint the image from the window onto the widget as an overlay QRect geom = ev->rect(); //atomic updates - geom.adjust(-1,-1,1,1); //add an additional pixel in each direction to be painted + 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; } -- cgit 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/NativeEmbedWidget.cpp | 66 +++++++++++++++++++++------- 1 file changed, 49 insertions(+), 17 deletions(-) (limited to 'src-qt5/core/libLumina/NativeEmbedWidget.cpp') 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. - } + } -- cgit From 21476cff5d19115466725aeb70cc5b2772768b67 Mon Sep 17 00:00:00 2001 From: Ken Moore Date: Fri, 21 Jul 2017 09:09:29 -0400 Subject: Now all the compositing is finished - fixed the last couple painting issues. --- src-qt5/core/libLumina/NativeEmbedWidget.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src-qt5/core/libLumina/NativeEmbedWidget.cpp') diff --git a/src-qt5/core/libLumina/NativeEmbedWidget.cpp b/src-qt5/core/libLumina/NativeEmbedWidget.cpp index ebefa994..ed0fd89c 100644 --- a/src-qt5/core/libLumina/NativeEmbedWidget.cpp +++ b/src-qt5/core/libLumina/NativeEmbedWidget.cpp @@ -155,7 +155,6 @@ void NativeEmbedWidget::resume(){ //syncWinSize(); //showWindow(); repaintWindow(); //update the cached image right away - this->parentWidget()->update(); } void NativeEmbedWidget::resyncWindow(){ @@ -185,6 +184,8 @@ void NativeEmbedWidget::resyncWindow(){ valList[0] = (uint32_t) sz.width(); xcb_configure_window(QX11Info::connection(), WIN->id(), mask, valList); xcb_flush(QX11Info::connection()); + syncWinSize(); + QTimer::singleShot(0, this, SLOT(repaintWindow()) ); } void NativeEmbedWidget::repaintWindow(){ @@ -194,7 +195,7 @@ void NativeEmbedWidget::repaintWindow(){ if(!tmp.isNull()){ winImage = tmp; }//else{ qDebug() << "Got Null Image!!"; } - this->update(); + this->parentWidget()->update(); } // ============== // PROTECTED @@ -231,7 +232,13 @@ void NativeEmbedWidget::paintEvent(QPaintEvent *ev){ 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); //} + if(winImage.size() == this->size()){ + 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. + }else{ + 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 -- cgit