diff options
Diffstat (limited to 'src-qt5/core/lumina-desktop-unified/src-desktop')
18 files changed, 464 insertions, 148 deletions
diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp index eefe6d7e..bfded781 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.cpp @@ -84,10 +84,6 @@ void DesktopManager::updateWallpaper(QString screen_id, int wkspace){ RootDesktopObject::instance()->ChangeWallpaper(screen_id,QUrl::fromLocalFile(wpaper).toString() ); } -void DesktopManager::updatePanels(QString panel_id){ - -} - void DesktopManager::updatePlugins(QString plugin_id){ } @@ -103,13 +99,13 @@ void DesktopManager::settingsChanged(DesktopSettings::File type){ case DesktopSettings::Desktop: QTimer::singleShot(0, this, SLOT(updateDesktopSettings()) ); case DesktopSettings::Panels: - QTimer::singleShot(0, this, SLOT(updatePanelSettings()) ); + QTimer::singleShot(1, this, SLOT(updatePanelSettings()) ); case DesktopSettings::Plugins: - QTimer::singleShot(0, this, SLOT(updatePluginSettings()) ); + QTimer::singleShot(2, this, SLOT(updatePluginSettings()) ); case DesktopSettings::ContextMenu: - QTimer::singleShot(0, this, SLOT(updateMenuSettings()) ); + QTimer::singleShot(3, this, SLOT(updateMenuSettings()) ); case DesktopSettings::Animation: - QTimer::singleShot(0, this, SLOT(updateAnimationSettings()) ); + QTimer::singleShot(4, this, SLOT(updateAnimationSettings()) ); default: break; //Do nothing - not a settings change we care about here @@ -148,14 +144,28 @@ void DesktopManager::syncTrayWindowList(){ // === PRIVATE SLOTS === void DesktopManager::updateDesktopSettings(){ qDebug() << "Update Desktop Settings..."; - QList<QScreen*> scrns= QApplication::screens(); + QList<QScreen*> scrns = QGuiApplication::screens(); int wkspace = Lumina::NWS->currentWorkspace(); for(int i=0; i<scrns.length(); i++){ updateWallpaper(scrns[i]->name(), wkspace); } } void DesktopManager::updatePanelSettings(){ - + QList<QScreen*> scrns = QGuiApplication::screens(); + int primary = QApplication::desktop()->primaryScreen(); + for(int i=0; i<scrns.length(); i++){ + ScreenObject *sObj = RootDesktopObject::instance()->screen(scrns[i]->name()); + if(sObj == 0){ continue; } //screen is not managed directly - skip it + QStringList ids = DesktopSettings::instance()->value(DesktopSettings::Panels, scrns[i]->name().replace("-","_")+"/active_ids", QStringList()).toStringList(); + if(ids.isEmpty() && (scrns.length()==1 || i==primary)){ + //Also look for the "default" panel id's for the primary/default screen + ids = DesktopSettings::instance()->value(DesktopSettings::Panels, "default/active_ids", QStringList()).toStringList(); + } + sObj->setPanels(ids); + } + //Now do the global-session panels + QStringList ids = DesktopSettings::instance()->value(DesktopSettings::Panels, "session/active_ids", QStringList()).toStringList(); + RootDesktopObject::instance()->setPanels(ids); //put the new ones in place } void DesktopManager::updatePluginSettings(){ diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.h b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.h index d4a0cf79..da42e477 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/DesktopManager.h @@ -23,7 +23,6 @@ public: private: void updateWallpaper(QString screen_id, int wkspace); - void updatePanels(QString panel_id); void updatePlugins(QString plugin_id); public slots: diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.cpp new file mode 100644 index 00000000..a74d2585 --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.cpp @@ -0,0 +1,65 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include <global-objects.h> +#include "QMLImageProvider.h" + +QMLImageProvider::QMLImageProvider(QQmlImageProviderBase::ImageType type) : QQuickImageProvider(type, 0){ + +} + +QMLImageProvider::~QMLImageProvider(){ + +} + +/*QMLImageProvider* QMLImageProvider::instance(){ + static QMLImageProvider *_prov = 0; + if(_prov==0){ _prov = new QMLImageProvider(); } + return _prov; +}*/ + +QImage QMLImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize){ + NativeWindowObject *win = Lumina::NWS->findWindow( id.section(":",1,1).toInt(), false); + if(win==0){ win = Lumina::NWS->findTrayWindow(id.section(":",1,1).toInt()); } + + if(!id.startsWith("image:")){ qDebug() << "Request Image:" << id << win << requestedSize; } + + QImage img(requestedSize,QImage::Format_RGB32); + if(win==0){ img.fill("black"); } //invalid window ID (should never happen) + else if(id.startsWith("image:")){ img = Lumina::NWS->GetWindowImage(win); } + else if(id.startsWith("icon:")){ + QIcon ico = win->property(NativeWindowObject::Icon).value<QIcon>(); + QList<QSize> sizes = ico.availableSizes(); + QSize sz(0,0); + //Just grab the largest size currently available + for(int i=0; i<sizes.length(); i++){ + if(sz.width()<sizes[i].width() && sz.height()<sizes[i].height()){ sz = sizes[i]; } + } + qDebug() << "Icon Sizes:" <<sizes; + img = ico.pixmap(sz).toImage(); + } + //qDebug() << "Got Window Image:" << img.size(); + if(img.size().isNull()){ + if(requestedSize.isValid()){ img = QImage(requestedSize,QImage::Format_RGB32); } + else{ img = QImage(QSize(64,64), QImage::Format_RGB32); } + img.fill("black"); + } + //qDebug() << "Final Window Image:" << img.size(); + if(size!=0){ + size->setHeight(img.height()); + size->setWidth( img.width() ); + } + if(requestedSize.isValid() && !requestedSize.isNull() && img.size()!=requestedSize){ + img = img.scaled(requestedSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + return img; +} + +QPixmap QMLImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize){ + qDebug() << "Pixmap Requested:" << id; + QImage img = requestImage(id, size, requestedSize); + return QPixmap::fromImage(img); +} diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.h b/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.h new file mode 100644 index 00000000..8719176e --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/QMLImageProvider.h @@ -0,0 +1,26 @@ +//=========================================== +// Lumina-desktop source code +// Copyright (c) 2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#ifndef _LUMINA_DESKTOP_QML_IMAGE_PROVIDER_H +#define _LUMINA_DESKTOP_QML_IMAGE_PROVIDER_H + +#include <QQuickImageProvider> +#include <QImage> +#include <QPixmap> +#include <QSize> + +class QMLImageProvider : public QQuickImageProvider{ +public: + QMLImageProvider(QQmlImageProviderBase::ImageType); + ~QMLImageProvider(); + + //static QMLImageProvider* instance(); + + virtual QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); + virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); +}; + +#endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/RootWindow.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/RootWindow.cpp index 0cfa4e6b..2ceff4a0 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/RootWindow.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/RootWindow.cpp @@ -5,6 +5,8 @@ // See the LICENSE file for full details //=========================================== #include "RootWindow.h" +#include "QMLImageProvider.h" +#include <QQmlImageProviderBase> RootWindow::RootWindow() : QObject(){ root_win = QWindow::fromWinId( QX11Info::appRootWindow() ); // @@ -16,6 +18,8 @@ RootWindow::RootWindow() : QObject(){ //Now setup the QQuickView root_view->setResizeMode(QQuickView::SizeRootObjectToView); root_view->engine()->rootContext()->setContextProperty("RootObject", root_obj); + root_view->engine()->addImageProvider("native_window", new QMLImageProvider(QQmlImageProviderBase::Image) ); + //root_view->engine()->addImageProvider("native_window_icon", new QMLImageProvider(QQmlImageProviderBase::Pixmap) ); RootDesktopObject::RegisterType(); //make sure object classes are registered with the QML subsystems } diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/desktop.pri b/src-qt5/core/lumina-desktop-unified/src-desktop/desktop.pri index f4a6882d..ee5ada62 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/desktop.pri +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/desktop.pri @@ -1,10 +1,12 @@ QT *= gui widgets qml quick SOURCES *= $${PWD}/RootWindow.cpp \ - $${PWD}/Desktopmanager.cpp + $${PWD}/Desktopmanager.cpp \ + $${PWD}/QMLImageProvider.cpp HEADERS *= $${PWD}/RootWindow.h \ - $${PWD}/DesktopManager.h + $${PWD}/DesktopManager.h \ + $${PWD}/QMLImageProvider.h #update the includepath so we can just #include as needed without paths INCLUDEPATH *= $${PWD} diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.cpp index e9049cdd..9bb78dd0 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.cpp @@ -21,7 +21,11 @@ void NativeWindowObject::RegisterType(){ NativeWindowObject::NativeWindowObject(WId id) : QObject(){ winid = id; frameid = 0; - dmgID = 0; + dmgID = dmg = 0; + geomTimer = new QTimer(this); + geomTimer->setSingleShot(true); + geomTimer->setInterval(50); //1/20 second + connect(geomTimer, SIGNAL(timeout()), this, SLOT(sendNewGeom()) ); } NativeWindowObject::~NativeWindowObject(){ @@ -62,17 +66,9 @@ void NativeWindowObject::setProperty(NativeWindowObject::Property prop, QVariant if(prop == NativeWindowObject::RelatedWindows){ relatedTo = val.value< QList<WId> >(); } else if(prop == NativeWindowObject::None || (!force && hash.value(prop)==val)){ return; } else if(prop == NativeWindowObject::WinImage){ - //special case - QImage is passed in, but QString is passed out (needed for QML) - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - val.value<QImage>().save(&buffer, "PNG"); - QString img("data:image/png;base64,"); - img.append(QString::fromLatin1(ba.toBase64().data())); - qDebug() << "Image Data Header:" << img.section(",",0,0); - hash.insert(prop, img); //save the string instead - } - else{ hash.insert(prop, val); } + //special case - This should never be actually set in the property hash + // it is loaded dynamically by the QMLImageProvider instead (prevent flickering/caching image) + } else{ hash.insert(prop, val); } emitSinglePropChanged(prop); emit PropertiesChanged(QList<NativeWindowObject::Property>() << prop, QList<QVariant>() << val); } @@ -83,15 +79,8 @@ void NativeWindowObject::setProperties(QList<NativeWindowObject::Property> props if(props[i] == NativeWindowObject::None || (!force && (hash.value(props[i]) == vals[i])) ){ props.removeAt(i); vals.removeAt(i); i--; continue; //Invalid property or identical value }else if(props[i] == NativeWindowObject::WinImage){ - //special case - QImage is passed in, but QString is passed out (needed for QML) - QByteArray ba; - QBuffer buffer(&ba); - buffer.open(QIODevice::WriteOnly); - vals[i].value<QImage>().save(&buffer, "PNG"); - QString img("data:image/png;base64,"); - img.append(QString::fromLatin1(ba.toBase64().data())); - qDebug() << "Image Data Header:" << img.section(",",0,0); - hash.insert(props[i], img); //save the string instead + //special case - This should never be actually set in the property hash + // it is loaded dynamically by the QMLImageProvider instead (prevent flickering/caching image) }else{ hash.insert(props[i], vals[i]); } @@ -141,9 +130,16 @@ QRect NativeWindowObject::geometry(){ return geom; } +void NativeWindowObject::setGeometryNow(QRect geom){ + updateGeometry(geom.x(), geom.y(), geom.width(), geom.height(), true); +} + // QML ACCESS FUNCTIONS (shortcuts for particular properties in a format QML can use) QString NativeWindowObject::winImage(){ - return this->property(NativeWindowObject::WinImage).toString(); + //Need to alternate something on the end to ensure that QML knows to fetch the new image (non-cached only) + if(dmg==0){ dmg = 1; } + else{ dmg = 0; } + return "image://native_window/image:"+QString::number(winid)+":"+QString::number(dmg); } QString NativeWindowObject::name(){ @@ -161,8 +157,11 @@ QString NativeWindowObject::shortTitle(){ return tmp; } -QIcon NativeWindowObject::icon(){ - return this->property(NativeWindowObject::Name).value<QIcon>(); +QString NativeWindowObject::icon(){ + if(icodmg==0){ icodmg=1; } + else{ icodmg = 0; } + qDebug() << "Window Icon:" << icodmg << this->property(NativeWindowObject::Icon).value<QIcon>().availableSizes(); + return "image://native_window/icon:"+QString::number(winid)+":"+QString::number(icodmg); } //QML Button states @@ -257,6 +256,23 @@ QRect NativeWindowObject::imageGeometry(){ return geom; } +void NativeWindowObject::updateGeometry(int x, int y, int width, int height, bool now){ + // Full frame+window geometry - go ahead and pull it apart and only update the interior window geom + QList<int> fgeom = this->property(NativeWindowObject::FrameExtents).value<QList<int> >(); + if(fgeom.isEmpty()){ fgeom << 0<<0<<0<<0; } //just in case (left/right/top/bottom) + QPoint pos(x+fgeom[0], y+fgeom[2]); + QSize sz(width-fgeom[0]-fgeom[1], height-fgeom[2]-fgeom[3]); + if(!now){ + newgeom = QRect(pos, sz); + //qDebug() << "Update Geometry:" << fgeom << QRect(x,y,width,height) << pos << sz; + //requestProperties(QList<NativeWindowObject::Property>() << NativeWindowObject::GlobalPos << NativeWindowObject::Size, QList<QVariant>() << pos << sz); + if(!geomTimer->isActive()){ geomTimer->start(); } + }else{ + requestProperties(QList<NativeWindowObject::Property>() << NativeWindowObject::GlobalPos << NativeWindowObject::Size , QList<QVariant>() << pos << sz ); + setProperties(QList<NativeWindowObject::Property>() << NativeWindowObject::GlobalPos << NativeWindowObject::Size , QList<QVariant>() << pos << sz ); + } +} + // ==== PUBLIC SLOTS === void NativeWindowObject::toggleVisibility(){ setProperty(NativeWindowObject::Visible, !property(NativeWindowObject::Visible).toBool() ); @@ -281,7 +297,9 @@ void NativeWindowObject::emitSinglePropChanged(NativeWindowObject::Property prop case NativeWindowObject::Name: emit nameChanged(); break; case NativeWindowObject::Title: - emit titleChanged(); break; + emit titleChanged(); + if(this->property(NativeWindowObject::ShortTitle).toString().isEmpty()){ emit shortTitleChanged(); } + break; case NativeWindowObject::ShortTitle: emit shortTitleChanged(); break; case NativeWindowObject::Icon: @@ -297,3 +315,10 @@ void NativeWindowObject::emitSinglePropChanged(NativeWindowObject::Property prop break; //do nothing otherwise } } + +void NativeWindowObject::sendNewGeom(){ + QList<NativeWindowObject::Property> props; props << NativeWindowObject::GlobalPos << NativeWindowObject::Size; + QList<QVariant> vals; vals << newgeom.topLeft() << newgeom.size(); + requestProperties(props, vals); + setProperties(props,vals); +} diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.h index e4f9d41e..6a63813e 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.h @@ -21,7 +21,7 @@ class NativeWindowObject : public QObject{ Q_PROPERTY( QString name READ name NOTIFY nameChanged) Q_PROPERTY( QString title READ title NOTIFY titleChanged) Q_PROPERTY( QString shortTitle READ shortTitle NOTIFY shortTitleChanged) - Q_PROPERTY( QIcon icon READ icon NOTIFY iconChanged) + Q_PROPERTY( QString icon READ icon NOTIFY iconChanged) Q_PROPERTY( bool sticky READ isSticky NOTIFY stickyChanged) //Button/Titlebar visibility Q_PROPERTY( bool showCloseButton READ showCloseButton NOTIFY winTypeChanged) @@ -38,6 +38,8 @@ public: enum State{ S_MODAL, S_STICKY, S_MAX_VERT, S_MAX_HORZ, S_SHADED, S_SKIP_TASKBAR, S_SKIP_PAGER, S_HIDDEN, S_FULLSCREEN, S_ABOVE, S_BELOW, S_ATTENTION }; enum Type{T_DESKTOP, T_DOCK, T_TOOLBAR, T_MENU, T_UTILITY, T_SPLASH, T_DIALOG, T_DROPDOWN_MENU, T_POPUP_MENU, T_TOOLTIP, T_NOTIFICATION, T_COMBO, T_DND, T_NORMAL }; enum Action {A_MOVE, A_RESIZE, A_MINIMIZE, A_SHADE, A_STICK, A_MAX_VERT, A_MAX_HORZ, A_FULLSCREEN, A_CHANGE_DESKTOP, A_CLOSE, A_ABOVE, A_BELOW}; + enum Location { TOP_LEFT, TOP, TOP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM, BOTTOM_LEFT, LEFT }; + Q_ENUM(Location) enum Property{ /*QVariant Type*/ None=0, /*null*/ @@ -90,13 +92,14 @@ public: void requestProperties(QList<NativeWindowObject::Property>, QList<QVariant>, bool force = false); Q_INVOKABLE QRect geometry(); //this returns the "full" geometry of the window (window + frame) + void setGeometryNow(QRect geom); // QML ACCESS FUNCTIONS (shortcuts for particular properties in a format QML can use) Q_INVOKABLE QString winImage(); Q_INVOKABLE QString name(); Q_INVOKABLE QString title(); Q_INVOKABLE QString shortTitle(); - Q_INVOKABLE QIcon icon(); + Q_INVOKABLE QString icon(); //QML Button states Q_INVOKABLE bool showCloseButton(); Q_INVOKABLE bool showMaxButton(); @@ -111,6 +114,7 @@ public: //QML Geometry reporting Q_INVOKABLE QRect frameGeometry(); Q_INVOKABLE QRect imageGeometry(); + Q_INVOKABLE void updateGeometry(int x, int y, int width, int height, bool now = false); //For QML to change the current window position public slots: Q_INVOKABLE void toggleVisibility(); @@ -123,17 +127,22 @@ private: //QWindow *WIN; WId winid, frameid; QList<WId> relatedTo; - unsigned int dmgID; + unsigned int dmgID, dmg, icodmg; + //Collation/Delay for window resize events + QTimer *geomTimer; + QRect newgeom; void emitSinglePropChanged(NativeWindowObject::Property); +private slots: + void sendNewGeom(); + signals: //General Notifications void PropertiesChanged(QList<NativeWindowObject::Property>, QList<QVariant>); void RequestPropertiesChange(WId, QList<NativeWindowObject::Property>, QList<QVariant>); void WindowClosed(WId); void WindowNotResponding(WId); //will be sent out if a window does not respond to a ping request - void VisualChanged(); //Action Requests (not automatically emitted - typically used to ask the WM to do something) //Note: "WId" should be the NativeWindowObject id() diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.cpp index 471da58f..9054f528 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.cpp @@ -5,6 +5,8 @@ // See the LICENSE file for full details //=========================================== #include "PanelObject.h" +#include <global-objects.h> + #include <QQmlEngine> #include <QDebug> @@ -42,3 +44,41 @@ void PanelObject::setGeometry( QRect newgeom ){ emit geomChanged(); } } + +void PanelObject::syncWithSettings(QRect parent_geom){ + //Read off all the settings + //qDebug() << "Sync Panel Settings:" << panel_id << parent_geom; + QString anchor = DesktopSettings::instance()->value(DesktopSettings::Panels, panel_id+"/anchor", "bottom").toString().toLower(); + QString align = DesktopSettings::instance()->value(DesktopSettings::Panels, panel_id+"/align", "center").toString().toLower(); + double length = DesktopSettings::instance()->value(DesktopSettings::Panels, panel_id+"/length_percent", 100).toDouble()/100.0; + double width = DesktopSettings::instance()->value(DesktopSettings::Panels, panel_id+"/width_font_percent", 2.1).toDouble(); + width = qRound(width * QApplication::fontMetrics().height() ); + this->setBackground( DesktopSettings::instance()->value(DesktopSettings::Panels, panel_id+"/background", "rgba(0,0,0,120)").toString() ); + // qDebug() << "Update Panel:" << panel_id << anchor+"/"+align << length << width; + //Now calculate the geometry of the panel + QRect newgeom; + //Figure out the size of the panel + if(anchor=="top" || anchor=="bottom"){ newgeom.setWidth( parent_geom.width()*length ); newgeom.setHeight(width); } + else{ newgeom.setWidth(width); newgeom.setHeight(parent_geom.height()*length); } + //qDebug() << " - Size:" << newgeom; + //Now figure out the location of the panel + if(align=="left" || align=="top"){ + if(anchor=="top" || anchor=="left"){ newgeom.moveTopLeft(QPoint(0,0)); } + else if(anchor=="right"){ newgeom.moveTopRight(QPoint(parent_geom.width(), 0)); } + else{ newgeom.moveBottomLeft(QPoint(0, parent_geom.height()) ); } //bottom by default + + }else if(align=="right" || align=="bottom"){ + if(anchor=="top"){ newgeom.moveTopRight(QPoint(parent_geom.width(),0)); } + else if(anchor=="left"){ newgeom.moveBottomLeft(QPoint(0, parent_geom.height())); } + else if(anchor=="right"){ newgeom.moveBottomRight(QPoint(parent_geom.width(), parent_geom.height())); } + else{ newgeom.moveBottomRight(QPoint(parent_geom.width(), parent_geom.height()) ); } + + }else{ //center + if(anchor=="top"){ newgeom.moveTopLeft(QPoint( (parent_geom.width()-newgeom.width())/2,0)); } + else if(anchor=="left"){ newgeom.moveTopLeft(QPoint(0, (parent_geom.height()-newgeom.height())/2 )); } + else if(anchor=="right"){ newgeom.moveTopRight(QPoint(parent_geom.width(), (parent_geom.height()-newgeom.height())/2 )); } + else{ newgeom.moveBottomLeft(QPoint( (parent_geom.width()-newgeom.width())/2, parent_geom.height()) ); } + } + //qDebug() << " - Calculated Geometry:" << newgeom; + this->setGeometry(newgeom); //Note: This is in parent-relative coordinates (not global) +} diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h index a788fa07..8cf59dee 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/PanelObject.h @@ -40,6 +40,7 @@ public: public slots: void setBackground(QString fileOrColor); void setGeometry(QRect newgeom); + void syncWithSettings(QRect parent_geom); signals: void backgroundChanged(); diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.cpp index 39dc30c1..07d4e463 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.cpp @@ -14,6 +14,7 @@ // === PUBLIC === RootDesktopObject::RootDesktopObject(QObject *parent) : QObject(parent){ updateScreens(); //make sure the internal list is updated right away + connect(this, SIGNAL(changePanels(QStringList)), this, SLOT(setPanels(QStringList)) ); } RootDesktopObject::~RootDesktopObject(){ @@ -87,6 +88,41 @@ void RootDesktopObject::setPanels(QList<PanelObject*> list){ emit panelsChanged(); } +void RootDesktopObject::setPanels(QStringList ids){ + //Make this thread-safe for object creation + if(this->thread() != QThread::currentThread()){ + //use internal signal/slot combo to change threads + this->emit changePanels(ids); + return; + } + + //Get the current bounding rectangle for the session + QRect total; + for(int i=0; i<s_objects.length(); i++){ + total = total.united(s_objects[i]->geometry()); + } + //First update/remove any current panel objects + bool change = false; + for(int i=0; i<panel_objects.length(); i++){ + if(ids.contains(panel_objects[i]->name()) ){ + ids.removeAll(panel_objects[i]->name()); //already handled + panel_objects[i]->syncWithSettings(total); + }else{ + panel_objects.takeAt(i)->deleteLater(); + i--; + change = true; //list changed + } + } + //Now create any new panel objects as needed + for(int i=0; i<ids.length(); i++){ + PanelObject *tmp = new PanelObject(ids[i], this); + tmp->syncWithSettings(total); + panel_objects << tmp; + change = true; //list changed + } + if(change){ emit panelsChanged(); } +} + void RootDesktopObject::setWindows(QList<NativeWindowObject*> list){ window_objects = list; emit windowsChanged(); diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.h index a4236596..ad0e538b 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/RootDesktopObject.h @@ -10,6 +10,7 @@ #define _LUMINA_DESKTOP_QML_BACKEND_ROOT_DESKTOP_OBJECT_H #include <global-includes.h> #include <ScreenObject.h> +#include <QThread> class RootDesktopObject : public QObject{ Q_OBJECT @@ -53,6 +54,9 @@ public slots: QString CurrentWallpaper(QString screen); void setPanels(QList<PanelObject*> list); + void setPanels(QStringList ids); + QList<PanelObject*> panelObjectList(){ return panel_objects; } + void setWindows(QList<NativeWindowObject*> list); private slots: @@ -66,5 +70,8 @@ signals: void mouseMoved(); void lockScreen(); void launchApplication(QString); + + //Internal signals for thread-safety + void changePanels(QStringList); }; #endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.cpp b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.cpp index 1b22c450..c754906d 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.cpp +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.cpp @@ -10,6 +10,7 @@ ScreenObject::ScreenObject(QScreen *scrn, QObject *parent) : QObject(parent){ bg_screen = scrn; + connect(this, SIGNAL(changePanels(QStringList)), this, SLOT(setPanels(QStringList)) ); } void ScreenObject::RegisterType(){ @@ -40,6 +41,37 @@ void ScreenObject::setPanels(QList<PanelObject*> list){ emit panelsChanged(); } +void ScreenObject::setPanels(QStringList ids){ + //Make this thread-safe for object creation + if(this->thread() != QThread::currentThread()){ + //use internal signal/slot combo to change threads + this->emit changePanels(ids); + return; + } + + //First update/remove any current panel objects + bool change = false; + for(int i=0; i<panel_objects.length(); i++){ + if(ids.contains(panel_objects[i]->name()) ){ + ids.removeAll(panel_objects[i]->name()); //already handled + panel_objects[i]->syncWithSettings(bg_screen->geometry()); + }else{ + panel_objects.takeAt(i)->deleteLater(); + i--; + change = true; //list changed + } + } + //Now create any new panel objects as needed + for(int i=0; i<ids.length(); i++){ + PanelObject *tmp = new PanelObject(ids[i], this); + tmp->syncWithSettings(bg_screen->geometry()); + panel_objects << tmp; + change = true; //list changed + } + if(change){ emit panelsChanged(); } +} + + //QML Read Functions QStringList ScreenObject::panels(){ //qDebug() << "Request Panels:" << panel_objects.length(); diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.h b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.h index 1afff6d2..250c9403 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.h +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/ScreenObject.h @@ -11,6 +11,7 @@ #include <QObject> #include <QString> #include <QScreen> +#include <QThread> #include "PanelObject.h" @@ -42,16 +43,24 @@ public: Q_INVOKABLE int height(); Q_INVOKABLE QStringList panels(); Q_INVOKABLE PanelObject* panel(QString id); + Q_INVOKABLE QRect geometry(){ return bg_screen->geometry(); } void setPanels(QList<PanelObject*> list); + QList<PanelObject*> panelObjectList(){ return panel_objects; } + public slots: + void setPanels(QStringList ids); void setBackground(QString fileOrColor); signals: void backgroundChanged(); void geomChanged(); void panelsChanged(); + + //Internal signals for thread-safety + void changePanels(QStringList); + }; #endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/NativeWindow.qml b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/NativeWindow.qml index 92263689..2150e37c 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/NativeWindow.qml +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/NativeWindow.qml @@ -5,6 +5,7 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import Lumina.Backend.NativeWindowObject 2.0 +import Lumina.Backend.RootDesktopObject 2.0 Rectangle { property NativeWindowObject object @@ -14,94 +15,119 @@ Rectangle { id: windowFrame border.width: 5 - //border.color: palette.window - color: palette.window + border.color: palette.highlight + radius: 5 + color: "transparent" //palette.window x: object.frameGeometry.x y: object.frameGeometry.y width: object.frameGeometry.width height: object.frameGeometry.height + onXChanged: { + windowFrame.object.updateGeometry(windowFrame.x, windowFrame.y, windowFrame.width, windowFrame.height) + } + onYChanged: { + windowFrame.object.updateGeometry(windowFrame.x, windowFrame.y, windowFrame.width, windowFrame.height) + } + MouseArea { id: resizeArea anchors.fill: parent - property int positionX: 0 - property int positionY: 0 - property int newWidth: 0 - property int newHeight: 0 - - onPositionChanged: { - var globalP = windowFrame.mapToGlobal(mouse.x, mouse.y) - if(positionY < windowFrame.y + 15 ) { - /*if(positionX < windowFrame.x + 15) { - console.log("Top Left"); - //Top Left - newWidth = windowFrame.width + (windowFrame.x - mouse.x) - newHeight = windowFrame.height + (windowFrame.y - mouse.y) - windowFrame.x = mouse.x - windowFrame.y = mouse.y - }else if(positionX > windowFrame.x + windowFrame.width - 15) { - console.log("Top Right"); - //Top Right - newX = positionX - mouse.x - newY = positionY - mouse.y - newWidth = windowFrame.width - (positionX - mouse.x) - newHeight = windowFrame.height + (windowFrame.y - mouse.y) - windowFrame.y = mouse.y - }else{*/ - //Top - windowFrame.height -= 1 - windowFrame.y = globalP.y - // } + drag.target: undefined + property int resizeDirection: NativeWindowObject.TOP_LEFT + property int positionX: -1 + property int positionY: -1 + + onPressed: { + //NOTE: This is only triggered for resize events + var globalP = windowFrame.mapToItem(rootCanvas, mouse.x, mouse.y) + positionX = globalP.x + positionY = globalP.y + if(positionY <= windowFrame.y + 10 ) { + if(positionX <= windowFrame.x + 10) + resizeDirection = NativeWindowObject.TOP_LEFT + else if(positionX >= windowFrame.x + windowFrame.width - 10) + resizeDirection = NativeWindowObject.TOP_RIGHT + else + resizeDirection = NativeWindowObject.TOP + }else if(positionY >= windowFrame.y + windowFrame.height - 10) { + if(positionX <= windowFrame.x + 10) + resizeDirection = NativeWindowObject.BOTTOM_LEFT + else if(positionX >= windowFrame.x + windowFrame.width - 10) + resizeDirection = NativeWindowObject.BOTTOM_RIGHT + else + resizeDirection = NativeWindowObject.BOTTOM + }else if(positionX <= windowFrame.x + 10) { + resizeDirection = NativeWindowObject.LEFT + }else if(positionX >= windowFrame.x + windowFrame.width - 10) { + resizeDirection = NativeWindowObject.RIGHT } -/*else if(mouse.x < windowFrame.x + 15) { - if(mouse.y > windowFrame.y + windowFrame.height - 15) { - //Bottom Left - newX = positionX - mouse.x - newWidth = windowFrame.width - newX - newHeight = windowFrame.height - newY - }else{ - //Left - } - }else if(mouse.y > windowFrame.y + windowFrame.height - 15) { - if(mouse.x > windowFrame.x + windowFrame.width - 15) { - //Bottom Right - }else{ - //Bottom - } - }else if(mouse.x > windowFrame.x + windowFrame.width - 15) { - //Right - } else { - console.log("Cursor error"); - }*/ + //console.log("Initial X: ", positionX, "Initial Y: ", positionY); + //console.log("Initial X Frame: ", windowFrame.x, "Initial Y Frame: ", windowFrame.y); } - } - - MouseArea { - id: dragArea - anchors.fill: titleBar - drag.target: windowFrame - drag.axis: Drag.XAndYAxis - onClicked: { console.log("dragArea"); } - //released: { function(); } - } - states: [ - State { - when: resizeArea.drag.held - PropertyChanges { target: Window; color:"red" } - }, - State { - when: dragArea.drag.held - AnchorChanges { target: windowFrame; anchors.verticalCenter: undefined; anchors.horizontalCenter: undefined } + onReleased: { + positionX = -1 + positionY = -1 + //windowFrame.object.updateGeometry(windowFrame.x, windowFrame.y, windowFrame.width, windowFrame.height) } - ] - + onPositionChanged: { + //NOTE: This is only triggered for resize events + if(positionX != -1 && positionY != -1) { + var globalP = windowFrame.mapToItem(rootCanvas, mouse.x, mouse.y) + /*console.log("Global P: ", globalP); + console.log("Position X: ", positionX, "Position Y: ", positionY) + console.log("Old Position : ", windowFrame.x, " , ", windowFrame.y) + console.log(resizeDirection);*/ + if(resizeDirection == NativeWindowObject.TOP_LEFT) { + windowFrame.height -= globalP.y - positionY + windowFrame.width -= globalP.x - positionX + windowFrame.y = globalP.y + windowFrame.x = globalP.x + }else if(resizeDirection == NativeWindowObject.TOP_RIGHT) { + //console.log("TOP RIGHT Old Height: ", windowFrame.height, "Old Width: ", windowFrame.width) + windowFrame.height -= globalP.y - positionY + windowFrame.width += globalP.x - positionX + //console.log("New Height: ", windowFrame.height, "New Width: ", windowFrame.width) + windowFrame.y = globalP.y + //console.log("New Position : ", windowFrame.x, " , ", windowFrame.y) + }else if(resizeDirection == NativeWindowObject.TOP) { + windowFrame.height -= globalP.y - positionY + windowFrame.y = globalP.y + } else if(resizeDirection == NativeWindowObject.RIGHT) { + windowFrame.width += globalP.x - positionX + } else if(resizeDirection == NativeWindowObject.BOTTOM_RIGHT) { + windowFrame.height += globalP.y - positionY + windowFrame.width += globalP.x - positionX + } else if(resizeDirection == NativeWindowObject.BOTTOM) { + windowFrame.height += globalP.y - positionY + } else if(resizeDirection == NativeWindowObject.BOTTOM_LEFT) { + windowFrame.width -= globalP.x - positionX + windowFrame.height += globalP.y - positionY + windowFrame.x = globalP.x + } else if(resizeDirection == NativeWindowObject.LEFT) { + windowFrame.width -= globalP.x - positionX + windowFrame.x = globalP.x + } + //Set a miniumum width and height as 80x50 + if(windowFrame.width < 80) { + windowFrame.width = 80 + } + if(windowFrame.height < 50) { + windowFrame.height = 50 + } + positionY = globalP.y + positionX = globalP.x + } + windowFrame.object.updateGeometry(windowFrame.x, windowFrame.y, windowFrame.width, windowFrame.height) + } + } Rectangle { id: titleBar - border.width: 2 - color: palette.window + border.width: 0 + color: palette.window height: 25 anchors.top: windowFrame.top anchors.right: windowFrame.right @@ -109,48 +135,51 @@ Rectangle { anchors.margins: windowFrame.border.width width: parent.width - RowLayout { - anchors.fill: titleBar - spacing: 0 + MouseArea { + id: dragArea + anchors.fill: parent + drag.target: windowFrame + drag.axis: Drag.XAndYAxis + //acceptedButtons: Qt.RightButton + //onClicked: contextMenu.open() + //released: { function(); } + } - Button { - id: otherButton - anchors.left: parent.left - Layout.fillHeight: true - iconSource: windowFrame.object.icon - } + ToolButton { + id: otherButton + anchors.left: parent.left + height: parent.height + iconSource: windowFrame.object.icon + } - Text { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - color: palette.windowText - text: windowFrame.object.shortTitle - - MouseArea { - acceptedButtons: Qt.RightButton - anchors.fill: parent - //onClicked: contextMenu.open() - } - } + Text { + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + color: palette.windowText + text: windowFrame.object.shortTitle + fontSizeMode: Text.Fit + } - Button { + RowLayout { + spacing: 0 + anchors.right: parent.right + height: parent.height + + ToolButton { id: minButton Layout.fillHeight: true iconName: "window-minimize" onClicked: { windowFrame.object.toggleVisibility() } } - Button { + ToolButton { id: maxButton Layout.fillHeight: true iconName: "window-maximize" //onClicked: { windowFrame.object.toggleMaximize() } } - Button { + ToolButton { id: closeButton Layout.fillHeight: true iconName: "document-close" @@ -161,6 +190,7 @@ Rectangle { Image { id: frameContents + cache: false source: windowFrame.object.winImage anchors.top: titleBar.bottom anchors.bottom: parent.bottom @@ -173,11 +203,10 @@ Rectangle { height: parent.height MouseArea { - width: parent.width; + width: parent.width height: parent.height anchors.fill: frameContents onClicked: { console.log(parent.mapToGlobal(mouse.x, mouse.y)); } - } } } diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Panel.qml b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Panel.qml index 846b5b55..556da5ec 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Panel.qml +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Panel.qml @@ -10,15 +10,13 @@ import QtQuick.Controls 1 import Lumina.Backend.PanelObject 2.0 -AnimatedImage { +Rectangle { //C++ backend object - property string screen_id + property string panel_id property PanelObject object //Normal geometries/placements - asynchronous: true - clip: true - source: object.background + color: object.background x: object.x y: object.y width: object.width diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/RootDesktop.qml b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/RootDesktop.qml index 9122ce5b..f48f7751 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/RootDesktop.qml +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/RootDesktop.qml @@ -66,4 +66,14 @@ Rectangle { z: 100+index } } + + //Setup the Panels + Repeater{ + model: RootObject.panels + QML.Panel{ + panel_id: modelData + object: RootObject.panel(panel_id) + z: 10100+index + } + } } diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Screen.qml b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Screen.qml index 3b83653a..82e7c89d 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Screen.qml +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-qml/Screen.qml @@ -9,6 +9,9 @@ import QtQuick.Window 2.2 import QtQuick.Controls 1 import Lumina.Backend.ScreenObject 2.0 +import Lumina.Backend.PanelObject 2.0 + +import "." as QML AnimatedImage { //C++ backend object @@ -23,4 +26,15 @@ AnimatedImage { y: object.y width: object.width height: object.height + + //Setup the Panels + Repeater{ + model: object.panels + QML.Panel{ + panel_id: modelData + object: parent.object.panel(panel_id) + z: 10000+index + } + } + } |