diff options
Diffstat (limited to 'src-qt5')
3 files changed, 315 insertions, 2 deletions
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 new file mode 100644 index 00000000..796dd5bc --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.cpp @@ -0,0 +1,175 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2017-2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +#include "NativeWindowObject.h" +#include <QQmlEngine> +#include <QDebug> + +// == QML Type Registration == +void NativeWindowObject::RegisterType(){ + static bool done = false; + if(done){ return; } + done=true; + qmlRegisterType<NativeWindowObject>("Lumina.Backend.NativeWindowObject",2,0, "NativeWindowObject"); +} + +// === PUBLIC === +NativeWindowObject::NativeWindowObject(WId id) : QObject(){ + winid = id; + frameid = 0; + dmgID = 0; +} + +NativeWindowObject::~NativeWindowObject(){ + hash.clear(); +} + +void NativeWindowObject::addFrameWinID(WId fid){ + frameid = fid; +} + +void NativeWindowObject::addDamageID(unsigned int dmg){ + dmgID = dmg; +} + +bool NativeWindowObject::isRelatedTo(WId tmp){ + return (relatedTo.contains(tmp) || winid == tmp || frameid == tmp); +} + +WId NativeWindowObject::id(){ + return winid; +} + +WId NativeWindowObject::frameId(){ + return frameid; +} + +unsigned int NativeWindowObject::damageId(){ + return dmgID; +} + +QVariant NativeWindowObject::property(NativeWindowObject::Property prop){ + if(hash.contains(prop)){ return hash.value(prop); } + else if(prop == NativeWindowObject::RelatedWindows){ return QVariant::fromValue(relatedTo); } + return QVariant(); //null variant +} + +void NativeWindowObject::setProperty(NativeWindowObject::Property prop, QVariant val, bool force){ + if(prop == NativeWindowObject::RelatedWindows){ relatedTo = val.value< QList<WId> >(); } + else if(prop == NativeWindowObject::None || (!force && hash.value(prop)==val)){ return; } + else{ hash.insert(prop, val); } + emitSinglePropChanged(prop); + emit PropertiesChanged(QList<NativeWindowObject::Property>() << prop, QList<QVariant>() << val); +} + +void NativeWindowObject::setProperties(QList<NativeWindowObject::Property> props, QList<QVariant> vals, bool force){ + for(int i=0; i<props.length(); i++){ + if(i>=vals.length()){ props.removeAt(i); i--; continue; } //no corresponding value for this property + 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 + hash.insert(props[i], vals[i]); + emitSinglePropChanged(props[i]); + } + emit PropertiesChanged(props, vals); +} + +void NativeWindowObject::requestProperty(NativeWindowObject::Property prop, QVariant val, bool force){ + if(prop == NativeWindowObject::None || prop == NativeWindowObject::RelatedWindows || (!force && hash.value(prop)==val) ){ return; } + emit RequestPropertiesChange(winid, QList<NativeWindowObject::Property>() << prop, QList<QVariant>() << val); +} + +void NativeWindowObject::requestProperties(QList<NativeWindowObject::Property> props, QList<QVariant> vals, bool force){ + //Verify/adjust inputs as needed + for(int i=0; i<props.length(); i++){ + if(i>=vals.length()){ props.removeAt(i); i--; continue; } //no corresponding value for this property + if(props[i] == NativeWindowObject::None || props[i] == NativeWindowObject::RelatedWindows || (!force && hash.value(props[i])==vals[i]) ){ props.removeAt(i); vals.removeAt(i); i--; continue; } //Invalid property or identical value + /*if( (props[i] == NativeWindowObject::Visible || props[i] == NativeWindowObject::Active) && frameid !=0){ + //These particular properties needs to change the frame - not the window itself + emit RequestPropertiesChange(frameid, QList<NativeWindowObject::Property>() << props[i], QList<QVariant>() << vals[i]); + props.removeAt(i); vals.removeAt(i); i--; + }*/ + } + emit RequestPropertiesChange(winid, props, vals); +} + +QRect NativeWindowObject::geometry(){ + //Calculate the "full" geometry of the window + frame (if any) + //Check that the size is between the min/max limitations + QSize size = hash.value(NativeWindowObject::Size).toSize(); + QSize min = hash.value(NativeWindowObject::MinSize).toSize(); + QSize max = hash.value(NativeWindowObject::MaxSize).toSize(); + if(min.isValid() && min.width() > size.width() ){ size.setWidth(min.width()); } + if(min.isValid() && min.height() > size.height()){ size.setHeight(min.height()); } + if(max.isValid() && max.width() < size.width() && max.width()>min.width()){ size.setWidth(max.width()); } + if(max.isValid() && max.height() < size.height() && max.height()>min.height()){ size.setHeight(max.height()); } + //Assemble the full geometry + QRect geom( hash.value(NativeWindowObject::GlobalPos).toPoint(), size ); + //Now adjust the window geom by the frame margins + QList<int> frame = hash.value(NativeWindowObject::FrameExtents).value< QList<int> >(); //Left,Right,Top,Bottom + //qDebug() << "Calculate Geometry:" << geom << frame; + if(frame.length()==4){ + geom = geom.adjusted( -frame[0], -frame[2], frame[1], frame[3] ); + } + //qDebug() << " - Total:" << geom; + return geom; +} + +// QML ACCESS FUNCTIONS (shortcuts for particular properties in a format QML can use) +QString NativeWindowObject::name(){ + return this->property(NativeWindowObject::Name).toString(); +} + +QString NativeWindowObject::title(){ + return this->property(NativeWindowObject::Title).toString(); +} + +QString NativeWindowObject::shortTitle(){ + return this->property(NativeWindowObject::ShortTitle).toString(); +} + +QIcon NativeWindowObject::icon(){ + return this->property(NativeWindowObject::Name).value<QIcon>(); +} + +bool NativeWindowObject::isSticky(){ + return (this->property(NativeWindowObject::Workspace).toInt()<0 || this->property(NativeWindowObject::States).value<QList<NativeWindowObject::State> >().contains(NativeWindowObject::S_STICKY) ); +} + +// ==== PUBLIC SLOTS === +void NativeWindowObject::toggleVisibility(){ + setProperty(NativeWindowObject::Visible, !property(NativeWindowObject::Visible).toBool() ); +} + +void NativeWindowObject::requestClose(){ + emit RequestClose(winid); +} + +void NativeWindowObject::requestKill(){ + emit RequestKill(winid); +} + +void NativeWindowObject::requestPing(){ + emit RequestPing(winid); +} + +// ==== PRIVATE ==== +void NativeWindowObject::emitSinglePropChanged(NativeWindowObject::Property prop){ + //Simple switch to emit the QML-usable signals as properties are changed + switch(prop){ + case NativeWindowObject::Name: + emit nameChanged(); break; + case NativeWindowObject::Title: + emit titleChanged(); break; + case NativeWindowObject::ShortTitle: + emit shortTitleChanged(); break; + case NativeWindowObject::Icon: + emit iconChanged(); break; + case NativeWindowObject::Workspace: + case NativeWindowObject::States: + emit stickyChanged(); break; + default: + break; //do nothing otherwise + } +} 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 new file mode 100644 index 00000000..fa1bf4de --- /dev/null +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/NativeWindowObject.h @@ -0,0 +1,136 @@ +//=========================================== +// Lumina-DE source code +// Copyright (c) 2017-2018, Ken Moore +// Available under the 3-clause BSD license +// See the LICENSE file for full details +//=========================================== +// This is a container object for setting/announcing changes +// in a native window's properties. +// The WM will usually run the "setProperty" function on this object, +// and any other classes/widgets which watch this window can act appropriatly after-the-fact +// Non-WM classes should use the "Request" signals to ask the WM to do something, and listen for changes later +//=========================================== +#ifndef _LUMINA_SOURCES_NATIVE_WINDOW_OBJECT_H +#define _LUMINA_SOURCES_NATIVE_WINDOW_OBJECT_H +#include "global-includes.h" + +class NativeWindowObject : public QObject{ + Q_OBJECT + // QML-ACCESSIBLE PROPERTIES + 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( bool sticky READ isSticky NOTIFY stickyChanged) + +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 Property{ /*QVariant Type*/ + None=0, /*null*/ + MinSize=1, /*QSize*/ + MaxSize=2, /*QSize*/ + Size=3, /*QSize*/ + GlobalPos=4, /*QPoint*/ + Title=5, /*QString*/ + ShortTitle=6, /*QString*/ + Icon=7, /*QIcon*/ + Name=8, /*QString*/ + Workspace=9, /*int*/ + States=10, /*QList<NativeWindowObject::State> : Current state of the window */ + WinTypes=11, /*QList<NativeWindowObject::Type> : Current type of window (typically does not change)*/ + WinActions=12, /*QList<NativeWindowObject::Action> : Current actions that the window allows (Managed/set by the WM)*/ + FrameExtents=13, /*QList<int> : [Left, Right, Top, Bottom] in pixels */ + RelatedWindows=14, /* QList<WId> - better to use the "isRelatedTo(WId)" function instead of reading this directly*/ + Active=15, /*bool*/ + Visible=16 /*bool*/ + }; + + static QList<NativeWindowObject::Property> allProperties(){ + //Return all the available properties (excluding "None" and "FrameExtents" (WM control only) ) + QList<NativeWindowObject::Property> props; + props << MinSize << MaxSize << Size << GlobalPos << Title << ShortTitle << Icon << Name << Workspace \ + << States << WinTypes << WinActions << RelatedWindows << Active << Visible; + return props; + }; + + static void RegisterType(); + + NativeWindowObject(WId id = 0); + ~NativeWindowObject(); + + void addFrameWinID(WId); + void addDamageID(unsigned int); + bool isRelatedTo(WId); + + WId id(); + WId frameId(); + unsigned int damageId(); + + //QWindow* window(); + + QVariant property(NativeWindowObject::Property); + void setProperty(NativeWindowObject::Property, QVariant, bool force = false); + void setProperties(QList<NativeWindowObject::Property>, QList<QVariant>, bool force = false); + void requestProperty(NativeWindowObject::Property, QVariant, bool force = false); + void requestProperties(QList<NativeWindowObject::Property>, QList<QVariant>, bool force = false); + + QRect geometry(); //this returns the "full" geometry of the window (window + frame) + + // QML ACCESS FUNCTIONS (shortcuts for particular properties in a format QML can use) + Q_INVOKABLE QString name(); + Q_INVOKABLE QString title(); + Q_INVOKABLE QString shortTitle(); + Q_INVOKABLE QIcon icon(); + Q_INVOKABLE bool isSticky(); + +public slots: + Q_INVOKABLE void toggleVisibility(); + Q_INVOKABLE void requestClose(); //ask the app to close the window (may/not depending on activity) + Q_INVOKABLE void requestKill(); //ask the WM to kill the app associated with this window (harsh - only use if not responding) + Q_INVOKABLE void requestPing(); //ask the app if it is still active (a WindowNotResponding signal will get sent out if there is no reply); + +private: + QHash <NativeWindowObject::Property, QVariant> hash; + //QWindow *WIN; + WId winid, frameid; + QList<WId> relatedTo; + unsigned int dmgID; + + void emitSinglePropChanged(NativeWindowObject::Property); + +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() + void RequestClose(WId); //Close the window + void RequestKill(WId); //Kill the window/app (usually from being unresponsive) + void RequestPing(WId); //Verify that the window is still active (such as not closing after a request + void RequestReparent(WId, WId, QPoint); //client window, frame window, relative origin point in frame + // System Tray Icon Embed/Unembed Requests + //void RequestEmbed(WId, QWidget*); + //void RequestUnEmbed(WId, QWidget*); + + // QML update signals + void nameChanged(); + void titleChanged(); + void shortTitleChanged(); + void iconChanged(); + void stickyChanged(); +}; + +// Declare the enumerations as Qt MetaTypes +Q_DECLARE_METATYPE(NativeWindowObject::Type); +Q_DECLARE_METATYPE(NativeWindowObject::Action); +Q_DECLARE_METATYPE(NativeWindowObject::State); +Q_DECLARE_METATYPE(NativeWindowObject::Property); + +#endif diff --git a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/src-cpp.pri b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/src-cpp.pri index 899f4968..25bdc019 100644 --- a/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/src-cpp.pri +++ b/src-qt5/core/lumina-desktop-unified/src-desktop/src-cpp/src-cpp.pri @@ -1,9 +1,11 @@ SOURCES *= $${PWD}/RootDesktopObject.cpp \ $${PWD}/ScreenObject.cpp \ - $${PWD}/PanelObject.cpp + $${PWD}/PanelObject.cpp \ + $${PWD}/NativeWindowObject.cpp HEADERS *= $${PWD}/RootDesktopObject.h \ $${PWD}/ScreenObject.h \ - $${PWD}/PanelObject.h + $${PWD}/PanelObject.h \ + $${PWD}/NativeWindowObject.h INCLUDEPATH *= $${PWD} |