aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/libLumina
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/core/libLumina')
-rw-r--r--src-qt5/core/libLumina/ExternalProcess.h26
-rw-r--r--src-qt5/core/libLumina/LuminaRandR-X11.cpp206
-rw-r--r--src-qt5/core/libLumina/LuminaRandR.cpp1
-rw-r--r--src-qt5/core/libLumina/LuminaRandR.h51
-rw-r--r--src-qt5/core/libLumina/LuminaRandR.pri12
-rw-r--r--src-qt5/core/libLumina/LuminaX11.cpp30
-rw-r--r--src-qt5/core/libLumina/LuminaX11.h13
-rw-r--r--src-qt5/core/libLumina/LuminaXDG.cpp5
-rw-r--r--src-qt5/core/libLumina/NativeWindow.cpp37
-rw-r--r--src-qt5/core/libLumina/NativeWindow.h81
-rw-r--r--src-qt5/core/libLumina/NativeWindow.pri8
-rw-r--r--src-qt5/core/libLumina/NativeWindowSystem.cpp221
-rw-r--r--src-qt5/core/libLumina/NativeWindowSystem.h92
-rw-r--r--src-qt5/core/libLumina/RootSubWindow.cpp110
-rw-r--r--src-qt5/core/libLumina/RootSubWindow.h51
-rw-r--r--src-qt5/core/libLumina/RootWindow.cpp23
-rw-r--r--src-qt5/core/libLumina/RootWindow.h12
-rw-r--r--src-qt5/core/libLumina/RootWindow.pri10
-rw-r--r--src-qt5/core/libLumina/test/main.cpp13
-rw-r--r--src-qt5/core/libLumina/test/test.pro7
20 files changed, 987 insertions, 22 deletions
diff --git a/src-qt5/core/libLumina/ExternalProcess.h b/src-qt5/core/libLumina/ExternalProcess.h
index 1325247f..8329c361 100644
--- a/src-qt5/core/libLumina/ExternalProcess.h
+++ b/src-qt5/core/libLumina/ExternalProcess.h
@@ -13,17 +13,40 @@
#include <QProcess>
#include <QString>
+#include <QTimer>
+#include <QApplication>
class ExternalProcess : public QProcess{
Q_OBJECT
+private:
+ bool cursorRestored;
+
private slots:
+ void resetCursor(){
+ if(!cursorRestored){
+ QApplication::restoreOverrideCursor();
+ cursorRestored = true;
+ }
+ }
+ void processStarting(){
+ if(!cursorRestored){
+ QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
+ QTimer::singleShot(15000, this, SLOT(resetCursor()) );
+ }
+ }
void processFinished(){
+ if(!cursorRestored){
+ QApplication::restoreOverrideCursor();
+ cursorRestored = true;
+ }
//Clean up this object
this->deleteLater();
}
+
public:
- ExternalProcess(QString logfile = "") : QProcess(){
+ ExternalProcess(QString logfile = "", bool manageCursors = true) : QProcess(){
this->setProcessChannelMode(QProcess::MergedChannels);
+ cursorRestored = !manageCursors;
if(logfile.isEmpty()){
this->setStandardOutputFile(QProcess::nullDevice());
}else{
@@ -32,6 +55,7 @@ public:
//Setup the connection for automatic cleanup
connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished()) );
}
+
~ExternalProcess(){
/*if(this->state() == QProcess::Running){
this->detach(); //about to close down the QProcess - detach the other program so it can continue functioning normally.
diff --git a/src-qt5/core/libLumina/LuminaRandR-X11.cpp b/src-qt5/core/libLumina/LuminaRandR-X11.cpp
new file mode 100644
index 00000000..85251b64
--- /dev/null
+++ b/src-qt5/core/libLumina/LuminaRandR-X11.cpp
@@ -0,0 +1,206 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "LuminaRandR.h"
+
+#include "xcb/randr.h"
+#include "xcb/xcb_atom.h"
+
+#include <QDebug>
+#include <QX11Info>
+
+static QString atomToName(xcb_atom_t atom){
+ xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name_unchecked(QX11Info::connection(), atom), NULL);
+ QString name = QString::fromLocal8Bit(xcb_get_atom_name_name(nreply), xcb_get_atom_name_name_length(nreply));
+ free(nreply);
+ return name;
+};
+
+//More efficient method for converting lots of atoms to strings
+static QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){
+ //qDebug() << "atomsToNames:" << num;
+ QList< xcb_get_atom_name_cookie_t > cookies;
+ //qDebug() << " - Get cookies";
+ for(unsigned int i=0; i<num; i++){ cookies << xcb_get_atom_name_unchecked(QX11Info::connection(), atoms[i]); }
+ QStringList names;
+ //qDebug() << " - Get names";
+ for(int i=0; i<cookies.length(); i++){
+ xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), cookies[i], NULL);
+ if(nreply==0){ continue; }
+ names << QString::fromLocal8Bit(xcb_get_atom_name_name(nreply), xcb_get_atom_name_name_length(nreply));
+ free(nreply);
+ }
+ return names;
+};
+
+class OutputDevice::p_objects{
+public:
+ xcb_atom_t monitor_atom;
+ QList<xcb_randr_output_t> outputs; //the actual output devices used by the monitor
+
+};
+
+//Global Listing of Devices
+QList<OutputDevice> OutputDevice::availableMonitors(){
+ QList<OutputDevice> list;
+ //Get the list of monitors
+ xcb_randr_get_monitors_cookie_t cookie = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), 1);
+ xcb_randr_get_monitors_reply_t *reply = xcb_randr_get_monitors_reply(QX11Info::connection(), cookie, NULL);
+ if(reply==0){
+ qDebug() << "Could not get monitor list";
+ return list;
+ }
+ xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(reply);
+ qDebug() << "Number of Monitors:" << xcb_randr_get_monitors_monitors_length(reply);
+ while(iter.rem>0){
+ qDebug() << "Found Monitor:";
+ //qDebug() << " Index:" << iter.index << "Rem:" << iter.rem;
+ QString name = atomToName(iter.data->name);
+ /*xcb_get_atom_name_reply_t *nreply = xcb_get_atom_name_reply(QX11Info::connection(), xcb_get_atom_name_unchecked(QX11Info::connection(), iter.data->name), NULL);
+ QString name = QString::fromLocal8Bit(xcb_get_atom_name_name(nreply), xcb_get_atom_name_name_length(nreply));
+ free(nreply);*/
+
+ qDebug() << " - Name:" << iter.data->name << name;
+ qDebug() << " - Primary:" << (iter.data->primary == 1);
+ qDebug() << " - Automatic:" << (iter.data->automatic == 1);
+ qDebug() << " - nOutput:" << iter.data->nOutput;
+ qDebug() << " - Geometry:" << QRect(iter.data->x, iter.data->y, iter.data->width, iter.data->height);
+ qDebug() << " - Physical Size (mm):" << iter.data->width_in_millimeters << "x" << iter.data->height_in_millimeters;
+ qDebug() << " - Number of outputs:" << xcb_randr_monitor_info_outputs_length(iter.data);
+ xcb_randr_monitor_info_next(&iter);
+ }
+
+ //Free up any objects we are done with
+ free(reply);
+ //Return the list
+ return list;
+}
+
+//FUNCTIONS (do not use directly - use the static list function instead)
+OutputDevice::OutputDevice(){
+ enabled = false;
+ p_obj = new p_objects();
+ p_obj->monitor_atom = 0;
+}
+
+OutputDevice::~OutputDevice(){
+
+}
+
+//Modification
+bool OutputDevice::setAsPrimary(){
+ if(isPrimary){ return true; }
+ if( !p_obj->outputs.isEmpty() ){
+ xcb_randr_set_output_primary (QX11Info::connection(), QX11Info::appRootWindow(), p_obj->outputs[0]);
+ isPrimary = true;
+ }
+ return isPrimary;
+}
+
+bool OutputDevice::disable(){
+ if(p_obj->monitor_atom!=0){
+ xcb_randr_delete_monitor(QX11Info::connection(), QX11Info::appRootWindow(), p_obj->monitor_atom);
+ p_obj->monitor_atom = 0;
+ return true;
+ }
+ return false;
+}
+
+void OutputDevice::enable(QRect geom){
+ //if no geom provided, will add as the right-most screen at optimal resolution
+ if(p_obj->monitor_atom!=0){ return; }
+ qDebug() << "Enable Monitor:" << geom;
+
+}
+
+void OutputDevice::changeResolution(QSize){
+
+}
+
+OutputDeviceList::OutputDeviceList(){
+ xcb_randr_get_screen_resources_reply_t *reply = xcb_randr_get_screen_resources_reply(QX11Info::connection(),
+ xcb_randr_get_screen_resources_unchecked(QX11Info::connection(), QX11Info::appRootWindow()),
+ NULL);
+ int outputnum = xcb_randr_get_screen_resources_outputs_length(reply);
+ qDebug() << "Probing Screen Resources:";
+ qDebug() << " - Number of Outputs:" << outputnum;
+ qDebug() << " - Number of CRTC's:" << xcb_randr_get_screen_resources_crtcs_length(reply);
+ int mode_len =xcb_randr_get_screen_resources_modes_length(reply);
+ qDebug() << " - Modes:" << mode_len;
+ for(int m=0; m<mode_len; m++){
+ xcb_randr_mode_info_t mode = xcb_randr_get_screen_resources_modes(reply)[m];
+ qDebug() << " -- Mode:" << mode.id;
+ qDebug() << " - Size:" << mode.width <<"x"<<mode.height;
+ }
+ //qDebug() << " -- " << atomsToNames( (xcb_atom_t*) xcb_randr_get_screen_resources_modes(reply), xcb_randr_get_screen_resources_modes_length(reply) );
+ qDebug() << " - Names:" << xcb_randr_get_screen_resources_names_length(reply);
+ //qDebug() << " -- " << atomsToNames( (xcb_atom_t*) xcb_randr_get_screen_resources_names(reply), xcb_randr_get_screen_resources_names_length(reply));
+ for(int i=0; i<outputnum; i++){
+ xcb_randr_output_t output = xcb_randr_get_screen_resources_outputs(reply)[i];
+ //Now display the info about this output
+ xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(),
+ xcb_randr_get_output_info_unchecked(QX11Info::connection(), output, QX11Info::appTime()),
+ NULL);
+ qDebug() << "==== Output Information #"+QString::number(i);
+
+ //Modes
+ qDebug() << "Number of Modes:" << xcb_randr_get_output_info_modes_length(info);
+
+
+ //Clones
+ qDebug() << "Number of Clones:" << xcb_randr_get_output_info_clones_length(info);
+
+ //Names
+ int name_len = xcb_randr_get_output_info_name_length(info);
+ qDebug() << "Names:" << atomsToNames( (xcb_atom_t*) xcb_randr_get_output_info_name(info), name_len);
+ for(int n=0; n<name_len; n++){
+ QString name = atomToName( xcb_randr_get_output_info_name(info)[n] );
+ qDebug() << " -- " << name;
+ }
+
+ //Properties
+ xcb_randr_list_output_properties_reply_t *pinfo = xcb_randr_list_output_properties_reply(QX11Info::connection(),
+ xcb_randr_list_output_properties_unchecked(QX11Info::connection(), output),
+ NULL);
+ int pinfo_len = xcb_randr_list_output_properties_atoms_length(pinfo);
+ qDebug() << "Properties:" << pinfo_len;
+ for(int p=0; p<pinfo_len; p++){
+ xcb_atom_t atom = xcb_randr_list_output_properties_atoms(pinfo)[p];
+ //Property Name
+ QString name = atomToName(atom);
+ //Property Value
+ xcb_randr_query_output_property_reply_t *pvalue = xcb_randr_query_output_property_reply(QX11Info::connection(),
+ xcb_randr_query_output_property_unchecked(QX11Info::connection(), output, atom),
+ NULL);
+ QStringList values = atomsToNames ( (xcb_atom_t*) xcb_randr_query_output_property_valid_values(pvalue), xcb_randr_query_output_property_valid_values_length(pvalue) ); //need to read values
+ /*for(int v=0; v<xcb_randr_query_output_property_valid_values_length(pvalue); v++){
+ //values << QString::number(xcb_randr_query_output_property_valid_values(pvalue)[v] );
+ values << atomToName( xcb_randr_query_output_property_valid_values(pvalue)[v] );
+ }*/
+ free(pvalue);
+ qDebug() << " -- " << name << "=" << values;
+
+ }
+ free(pinfo);
+
+ free(info);
+ }
+
+ free(reply);
+}
+
+OutputDeviceList::~OutputDeviceList(){
+
+}
+
+//Simplification functions for dealing with multiple monitors
+void OutputDeviceList::setPrimaryMonitor(QString id){
+
+}
+
+void OutputDeviceList::disableMonitor(QString id){
+
+}
diff --git a/src-qt5/core/libLumina/LuminaRandR.cpp b/src-qt5/core/libLumina/LuminaRandR.cpp
deleted file mode 100644
index eefc5aa8..00000000
--- a/src-qt5/core/libLumina/LuminaRandR.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "LuminaRandR.h"
diff --git a/src-qt5/core/libLumina/LuminaRandR.h b/src-qt5/core/libLumina/LuminaRandR.h
index 3cdff651..448c676d 100644
--- a/src-qt5/core/libLumina/LuminaRandR.h
+++ b/src-qt5/core/libLumina/LuminaRandR.h
@@ -1,35 +1,70 @@
//===========================================
// Lumina-DE source code
-// Copyright (c) 2016, Ken Moore
+// Copyright (c) 2017, Ken Moore
// Available under the 3-clause BSD license
// See the LICENSE file for full details
//===========================================
// This class governs all the xcb/randr interactions
// and provides simpler Qt-based functions for use elsewhere
//===========================================
+#ifndef _LUMINA_LIBRARY_RANDR_MONITORS_H
+#define _LUMINA_LIBRARY_RANDR_MONITORS_H
//Qt includes
#include <QSize>
+#include <QString>
+#include <QPoint>
+#include <QRect>
+#include <QList>
-#include "xcb/randr.h"
-class outputDevice{
+class OutputDevice{
public:
QString id; //output ID
bool enabled;
+ bool isPrimary;
//Monitor Geometry
QPoint geom; //geometry of monitor within session
//Monitor Resolution
QSize cRes; //current resolution of the monitor (could be different from geom.size() if panning is enabled)
QList<QSize> availRes; //available resolutions supported by the monitor
//Refresh Rate
- int cHz; //current refresh rate
- QList<int> availHz; //available refresh rates
+ //int cHz; //current refresh rate
+ //QList<int> availHz; //available refresh rates
//Expand this later to include:
// panning (current/possible)
// rotation (current/possible)
- //FUNCTIONS
-
- //Modification
+ //Global Listing of Devices
+ static QList<OutputDevice> availableMonitors();
+
+ //FUNCTIONS (do not use directly - use the static list function instead)
+ OutputDevice();
+ ~OutputDevice();
+
+ //Modification
+ bool setAsPrimary();
+ bool disable();
+ void enable(QRect geom = QRect()); //if no geom provided, will add as the right-most screen at optimal resolution
+ void changeResolution(QSize);
+
+ //Now define a simple public_objects class so that each implementation
+ // has a storage container for placing private objects as needed
+ class p_objects;
+ p_objects* p_obj;
+};
+
+class OutputDeviceList : public QList<OutputDevice>{
+public:
+ OutputDeviceList();
+ ~OutputDeviceList();
+
+ //Simplification functions for dealing with multiple monitors
+ void setPrimaryMonitor(QString id);
+ void disableMonitor(QString id);
+ //void enableMonitor(QString id,
+
+private:
+
};
+#endif
diff --git a/src-qt5/core/libLumina/LuminaRandR.pri b/src-qt5/core/libLumina/LuminaRandR.pri
new file mode 100644
index 00000000..0812819f
--- /dev/null
+++ b/src-qt5/core/libLumina/LuminaRandR.pri
@@ -0,0 +1,12 @@
+#include("$${PWD}/../../OS-detect.pri")
+
+QT *= x11extras
+
+#X11/XCB includes
+LIBS *= -lxcb -lxcb-randr
+SOURCES *= $${PWD}/LuminaRandR-X11.cpp
+
+#General API/Header
+HEADERS *= $${PWD}/LuminaRandR.h
+
+INCLUDEPATH *= ${PWD}
diff --git a/src-qt5/core/libLumina/LuminaX11.cpp b/src-qt5/core/libLumina/LuminaX11.cpp
index a8016460..e9eb4b7c 100644
--- a/src-qt5/core/libLumina/LuminaX11.cpp
+++ b/src-qt5/core/libLumina/LuminaX11.cpp
@@ -1470,7 +1470,17 @@ void LXCB::WM_ICCCM_SetProtocols(WId win, LXCB::ICCCM_PROTOCOLS flags){
// _NET_SUPPORTED (Root)
void LXCB::WM_Set_Root_Supported(){
//NET_WM standards (ICCCM implied - no standard way to list those)
- xcb_atom_t list[] = {};
+ xcb_atom_t list[] = {EWMH._NET_WM_NAME,
+ EWMH._NET_WM_ICON,
+ EWMH._NET_WM_ICON_NAME,
+ EWMH._NET_WM_DESKTOP,
+ /*_NET_WINDOW_TYPE (and all the various types)*/
+ EWMH._NET_WM_WINDOW_TYPE, EWMH._NET_WM_WINDOW_TYPE_DESKTOP, EWMH._NET_WM_WINDOW_TYPE_DOCK,
+ EWMH._NET_WM_WINDOW_TYPE_TOOLBAR, EWMH._NET_WM_WINDOW_TYPE_MENU, EWMH._NET_WM_WINDOW_TYPE_UTILITY,
+ EWMH._NET_WM_WINDOW_TYPE_SPLASH, EWMH._NET_WM_WINDOW_TYPE_DIALOG, EWMH._NET_WM_WINDOW_TYPE_NORMAL,
+ EWMH._NET_WM_WINDOW_TYPE_DROPDOWN_MENU, EWMH._NET_WM_WINDOW_TYPE_POPUP_MENU, EWMH._NET_WM_WINDOW_TYPE_TOOLTIP,
+ EWMH._NET_WM_WINDOW_TYPE_NOTIFICATION, EWMH._NET_WM_WINDOW_TYPE_COMBO, EWMH._NET_WM_WINDOW_TYPE_DND,
+ };
xcb_ewmh_set_supported(&EWMH, QX11Info::appScreen(), 0,list);
}
@@ -1609,7 +1619,23 @@ WId LXCB::WM_Get_Active_Window(){
}
void LXCB::WM_Set_Active_Window(WId win){
- xcb_ewmh_set_active_window(&EWMH, QX11Info::appScreen(), win);
+ xcb_ewmh_set_active_window(&EWMH, QX11Info::appScreen(), win);
+ //Also send the active window a message to take input focus
+ //Send the window a WM_TAKE_FOCUS message
+ if(atoms.isEmpty()){ createWMAtoms(); } //need these atoms
+ xcb_client_message_event_t event;
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = win;
+ event.type = ATOMS[atoms.indexOf("WM_PROTOCOLS")];
+ event.data.data32[0] = ATOMS[atoms.indexOf("WM_TAKE_FOCUS")];
+ event.data.data32[1] = XCB_TIME_CURRENT_TIME; //CurrentTime;
+ event.data.data32[2] = 0;
+ event.data.data32[3] = 0;
+ event.data.data32[4] = 0;
+
+ xcb_send_event(QX11Info::connection(), 0, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *) &event);
+ xcb_flush(QX11Info::connection());
}
// _NET_WORKAREA
diff --git a/src-qt5/core/libLumina/LuminaX11.h b/src-qt5/core/libLumina/LuminaX11.h
index 2c741111..2f66ce06 100644
--- a/src-qt5/core/libLumina/LuminaX11.h
+++ b/src-qt5/core/libLumina/LuminaX11.h
@@ -23,7 +23,6 @@
#include <QObject>
#include <QFlags>
-
#include <xcb/xcb_ewmh.h>
//SYSTEM TRAY STANDARD DEFINITIONS
@@ -67,6 +66,18 @@ public:
|| width_inc>=0 || height_inc>=0 || min_aspect_num>=0 || min_aspect_den>=0 || max_aspect_num>=0 || max_aspect_den>=0 \
|| base_width>=0 || base_height>=0 || win_gravity>0 );
}
+ bool validMaxSize(){
+ return (max_width>0 && max_width>=min_width) && (max_height>0 && max_height>=min_height);
+ }
+ bool validMinSize(){
+ return (min_width>0 && min_height>0);
+ }
+ bool validBaseSize(){
+ return (base_width>0 && base_height>0);
+ }
+ bool validSize(){ //only check this if the base sizes are invalid (this is the old spec and should not be used any more)
+ return (x>0 && y>0);
+ }
};
//simple data structure for passing around the XRANDR information
diff --git a/src-qt5/core/libLumina/LuminaXDG.cpp b/src-qt5/core/libLumina/LuminaXDG.cpp
index d92285c5..38128fc7 100644
--- a/src-qt5/core/libLumina/LuminaXDG.cpp
+++ b/src-qt5/core/libLumina/LuminaXDG.cpp
@@ -127,9 +127,8 @@ void XDGDesktop::sync(){
else if(var=="Type" && insection){
if(val.toLower()=="application"){ type = XDGDesktop::APP; }
else if(val.toLower()=="link"){ type = XDGDesktop::LINK; }
- else if(val.toLower()=="dir"){ type = XDGDesktop::DIR; }
+ else if(val.toLower().startsWith("dir")){ type = XDGDesktop::DIR; } //older specs are "Dir", newer specs are "Directory"
else{ type = XDGDesktop::BAD; } //Unknown type
- //hasType = true;
}
} //end reading file
file.clear(); //done with contents of file
@@ -176,7 +175,7 @@ bool XDGDesktop::isValid(bool showAll){
//if(DEBUG && !ok){ qDebug() << " - Link with missing URL"; }
break;
case XDGDesktop::DIR:
- ok = !path.isEmpty();
+ ok = !path.isEmpty() && QFile::exists(path);
//if(DEBUG && !ok){ qDebug() << " - Dir with missing path"; }
break;
default:
diff --git a/src-qt5/core/libLumina/NativeWindow.cpp b/src-qt5/core/libLumina/NativeWindow.cpp
new file mode 100644
index 00000000..bd42ecaa
--- /dev/null
+++ b/src-qt5/core/libLumina/NativeWindow.cpp
@@ -0,0 +1,37 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "NativeWindow.h"
+
+// === PUBLIC ===
+NativeWindow::NativeWindow(WId id) : QObject(){
+ winid = id;
+ WIN = QWindow::fromWinId(winid);
+}
+
+NativeWindow::~NativeWindow(){
+ hash.clear();
+ //WIN->deleteLater(); //This class only deals with Native windows which were created outside the app - they need to be cleaned up outside the app too
+}
+
+WId NativeWindow::id(){
+ return winid;
+}
+
+QWindow* NativeWindow::window(){
+ return WIN;
+}
+
+QVariant NativeWindow::property(NativeWindow::Property prop){
+ if(hash.contains(prop)){ return hash.value(prop); }
+ return QVariant(); //null variant
+}
+
+void NativeWindow::setProperty(NativeWindow::Property prop, QVariant val){
+ if(prop == NativeWindow::None){ return; }
+ hash.insert(prop, val);
+ emit PropertyChanged(prop, val);
+}
diff --git a/src-qt5/core/libLumina/NativeWindow.h b/src-qt5/core/libLumina/NativeWindow.h
new file mode 100644
index 00000000..59b955c3
--- /dev/null
+++ b/src-qt5/core/libLumina/NativeWindow.h
@@ -0,0 +1,81 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2017, 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_DESKTOP_NATIVE_WINDOW_H
+#define _LUMINA_DESKTOP_NATIVE_WINDOW_H
+
+#include <QString>
+#include <QRect>
+#include <QSize>
+#include <QObject>
+#include <QWindow>
+#include <QHash>
+#include <QVariant>
+
+class NativeWindow : public QObject{
+ Q_OBJECT
+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, /*null*/
+ MinSize, /*QSize*/
+ MaxSize, /*QSize*/
+ Size, /*QSize*/
+ GlobalPos, /*QPoint*/
+ Title, /*QString*/
+ ShortTitle, /*QString*/
+ Icon, /*QIcon*/
+ Name, /*QString*/
+ Workspace, /*int*/
+ States, /*QList<NativeWindow::State> : Current state of the window */
+ WinTypes, /*QList<NativeWindow::Type> : Current type of window (typically does not change)*/
+ WinActions, /*QList<NativeWindow::Action> : Current actions that the window allows (Managed/set by the WM)*/
+ Active, /*bool*/
+ Visible /*bool*/
+ };
+
+
+ NativeWindow(WId id);
+ ~NativeWindow();
+
+ WId id();
+ QWindow* window();
+
+ QVariant property(NativeWindow::Property);
+ void setProperty(NativeWindow::Property, QVariant);
+
+private:
+ QHash <NativeWindow::Property, QVariant> hash;
+ QWindow *WIN;
+ WId winid;
+
+signals:
+ //General Notifications
+ void PropertyChanged(NativeWindow::Property, QVariant);
+ void WindowClosed(WId);
+
+ //Action Requests (not automatically emitted - typically used to ask the WM to do something)
+ //Note: "WId" should be the NativeWindow id()
+ void RequestActivate(WId); //Activate the window
+ void RequestClose(WId); //Close the window
+ void RequestSetVisible(WId, bool); //Minimize/restore visiblility
+ void RequestSetGeometry(WId, QRect); //Register the location/size of the window
+ void RequestSetFrameExtents(WId, QList<int>); //Register the size of the frame around the window [Left,Right, Top,Bottom] in pixels
+
+ // System Tray Icon Embed/Unembed Requests
+ //void RequestEmbed(WId, QWidget*);
+ //void RequestUnEmbed(WId, QWidget*);
+};
+#endif
diff --git a/src-qt5/core/libLumina/NativeWindow.pri b/src-qt5/core/libLumina/NativeWindow.pri
new file mode 100644
index 00000000..4a585a06
--- /dev/null
+++ b/src-qt5/core/libLumina/NativeWindow.pri
@@ -0,0 +1,8 @@
+
+# Files
+SOURCES *= $${PWD}/NativeWindow.cpp
+
+HEADERS *= $${PWD}/NativeWindow.h
+
+INCLUDEPATH *= ${PWD}
+
diff --git a/src-qt5/core/libLumina/NativeWindowSystem.cpp b/src-qt5/core/libLumina/NativeWindowSystem.cpp
new file mode 100644
index 00000000..c8e6d483
--- /dev/null
+++ b/src-qt5/core/libLumina/NativeWindowSystem.cpp
@@ -0,0 +1,221 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This is the XCB version of the NativeWindowSystem class,
+// used for interacting with the X11 display system on BSD/Linux/Unix systems
+//===========================================
+#include "NativeWindowSystem.h"
+
+//Additional Qt includes
+#include <QX11Info>
+#include <QDebug>
+
+//XCB Library functions
+#include <xcb/xcb_ewmh.h>
+
+//XCB Library includes
+#include <xcb/xcb.h>
+#include <xcb/xcb_atom.h>
+#include <xcb/xproto.h>
+#include <xcb/xcb_ewmh.h>
+#include <xcb/xcb_icccm.h>
+#include <xcb/xcb_image.h>
+#include <xcb/xcb_aux.h>
+#include <xcb/composite.h>
+#include <xcb/damage.h>
+
+//XLib includes (XCB Damage lib does not appear to register for damage events properly)
+#include <X11/extensions/Xdamage.h>
+
+//SYSTEM TRAY STANDARD DEFINITIONS
+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0
+#define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define SYSTEM_TRAY_BEGIN_MESSAGE 1
+#define SYSTEM_TRAY_CANCEL_MESSAGE 2
+
+#define URGENCYHINT (1L << 8) //For window urgency detection
+
+#define ROOT_WIN_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \
+ XCB_EVENT_MASK_BUTTON_PRESS | \
+ XCB_EVENT_MASK_STRUCTURE_NOTIFY | \
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | \
+ XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | \
+ XCB_EVENT_MASK_POINTER_MOTION | \
+ XCB_EVENT_MASK_PROPERTY_CHANGE | \
+ XCB_EVENT_MASK_FOCUS_CHANGE | \
+ XCB_EVENT_MASK_ENTER_WINDOW)
+
+//Internal XCB private objects class
+class NativeWindowSystem::p_objects{
+public:
+ xcb_ewmh_connection_t EWMH; //This is where all the screen info and atoms are located
+ QHash<QString, xcb_atom_t> ATOMS;
+ xcb_screen_t *root_screen;
+ xcb_window_t root_window, wm_window, tray_window;
+
+ //Functions for setting up these objects as needed
+ bool init_ATOMS(){
+ QStringList atoms;
+ atoms << "WM_TAKE_FOCUS" << "WM_DELETE_WINDOW" << "WM_PROTOCOLS" << "WM_CHANGE_STATE" << "_NET_SYSTEM_TRAY_OPCODE" << "_NET_SYSTEM_TRAY_ORIENTATION" << "_NET_SYSTEM_TRAY_VISUAL" << QString("_NET_SYSTEM_TRAY_S%1").arg(QString::number(QX11Info::appScreen()));
+ //Create all the requests for the atoms
+ QList<xcb_intern_atom_reply_t*> reply;
+ for(int i=0; i<atoms.length(); i++){
+ reply << xcb_intern_atom_reply(QX11Info::connection(), \
+ xcb_intern_atom(QX11Info::connection(), 0, atoms[i].length(), atoms[i].toLocal8Bit()), NULL);
+ }
+ //Now evaluate all the requests and save the atoms
+ for(int i=0; i<reply.length(); i++){ //NOTE: this will always be the same length as the "atoms" list
+ if(reply[i]!=0){
+ obj->ATOMS.insert(atoms[i], reply[i]->atom);
+ free(reply[i]); //done with this reply
+ }else{
+ //Invalid atom - could not be created
+ qDebug() << "Could not initialize XCB atom:" << atoms[i];
+ }
+ } //loop over reply
+ return (obj->ATOMS.keys.length() == atoms.length());
+ }
+
+ bool register_wm(){
+ uint32_t value_list[1] = {ROOT_WIN_EVENT_MASK};
+ xcb_generic_error_t *status = xcb_request_check( QX11Info::connection(), xcb_change_window_attributes_checked(QX11Info::connection(), root_window, XCB_CW_EVENT_MASK, value_list));
+ if(status!=0){ return false; }
+ uint32_t params[] = {1};
+ wm_window = xcb_generate_id(QX11Info::connection()); //need a new ID
+ xcb_create_window(QX11Info::connection(), root_screen->root_depth, \
+ win, root_window, -1, -1, 1, 1, 0, \
+ XCB_WINDOW_CLASS_INPUT_OUTPUT, root_screen->root_visual, \
+ XCB_CW_OVERRIDE_REDIRECT, params);
+ if(wm_window==0){ return false; }
+ //Set the _NET_SUPPORTING_WM property on the root window first
+ xcb_ewmh_set_supporting_wm_check(&EWMH, root_window, wm_window);
+ //Also set this property on the child window (pointing to itself)
+ xcb_ewmh_set_supporting_wm_check(&EWMH, wm_window, wm_window);
+ //Now also setup the root event mask on the wm_window
+ status = xcb_request_check( QX11Info::connection(), xcb_change_window_attributes_checked(QX11Info::connection(), wm_window, XCB_CW_EVENT_MASK, value_list));
+ if(status!=0){ return false; }
+ return true;
+ }
+
+ bool startSystemTray{
+ xcb_atom_t _NET_SYSTEM_TRAY_S = ATOMS.value(QString("_NET_SYSTEM_TRAY_S%1").arg(QString::number(QX11Info::appScreen())) );
+ //Make sure that there is no other system tray running
+ xcb_get_selection_owner_reply_t *ownreply = xcb_get_selection_owner_reply(QX11Info::connection(), \
+ xcb_get_selection_owner_unchecked(QX11Info::connection(), _NET_SYSTEM_TRAY_S), NULL);
+ if(ownreply==0){
+ qWarning() << " - Could not get owner selection reply";
+ return false;
+ }else if(ownreply->owner != 0){
+ free(ownreply);
+ qWarning() << " - An alternate system tray is currently in use";
+ return false;
+ }
+ free(ownreply);
+ //Now create the window to use (just offscreen)
+ //TODO
+ }
+
+}; //end private objects class
+
+
+//inline functions for setting up the internal objects
+
+
+// === PUBLIC ===
+NativeWindowSystem::NativeWindowSystem() : QObject(){
+ obj = 0;
+}
+
+NativeWindowSystem::~NativeWindowSystem(){
+ xcb_ewmh_connection_wipe(obj->EWMH);
+ free(obj);
+}
+
+//Overarching start/stop functions
+bool NativeWindowSystem::start(){
+ //Initialize the XCB/EWMH objects
+ if(obj==0){
+ obj = new p_objects(); } //instantiate the private objects
+ obj->wm_window = 0;
+ obj->tray_window = 0;
+ xcb_intern_atom_cookie_t *cookie = xcb_ewmh_init_atoms(QX11Info::connection(), &obj->EWMH);
+ if(!xcb_ewmh_init_atoms_replies(&obj->EWMH, cookie, NULL) ){
+ qDebug() << "Error with XCB atom initializations";
+ return false;
+ }
+ obj->root_screen = xcb_aux_get_screen(QX11Info::connection(), QX11Info::appScreen());
+ obj->root_window = obj->root_screen->root; //simplification for later - minor duplication of memory (unsigned int)
+ //Initialize all the extra atoms that the EWMH object does not have
+ if( !obj->init_ATOMS() ){ return false; }
+ } //Done with private object init
+
+ return true;
+}
+
+void NativeWindowSystem::stop(){
+
+}
+
+// === PRIVATE ===
+void NativeWindowSystem::UpdateWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props){
+
+}
+
+// === PUBLIC SLOTS ===
+//These are the slots which are only used by the desktop system itself or the NativeWindowEventFilter
+void NativeWindowSystem::RegisterVirtualRoot(WId){
+
+}
+
+//NativeWindowEventFilter interactions
+void NativeWindowSystem::NewWindowDetected(WId){
+
+}
+
+void NativeWindowSystem::WindowCloseDetected(WId){
+
+}
+
+void NativeWindowSystem::WindowPropertyChanged(WId, NativeWindow::Property){
+
+}
+
+void NativeWindowSystem::NewKeyPress(int keycode){
+
+}
+
+void NativeWindowSystem::NewKeyRelease(int keycode){
+
+}
+
+void NativeWindowSystem::NewMousePress(int buttoncode){
+
+}
+
+void NativeWindowSystem::NewMouseRelease(int buttoncode){
+
+}
+
+// === PRIVATE SLOTS ===
+//These are the slots which are built-in and automatically connected when a new NativeWindow is created
+void NativeWindowSystem::RequestActivate(WId){
+
+}
+void NativeWindowSystem::RequestClose(WId){
+
+}
+
+void NativeWindowSystem::RequestSetVisible(WId, bool){
+
+}
+void NativeWindowSystem::RequestSetGeometry(WId, QRect){
+
+}
+void NativeWindowSystem::RequestSetFrameExtents(WId, QList<int>){
+ //[Left,Top,Right,Bottom] in pixels
+
+}
diff --git a/src-qt5/core/libLumina/NativeWindowSystem.h b/src-qt5/core/libLumina/NativeWindowSystem.h
new file mode 100644
index 00000000..ef169059
--- /dev/null
+++ b/src-qt5/core/libLumina/NativeWindowSystem.h
@@ -0,0 +1,92 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This is a Qt5/Lumina wrapper around native graphics system calls
+// It is primarily designed around the creation/modification of instances of
+// the "NativeWindow" class for passing information around
+//===========================================
+#ifndef _LUMINA_NATIVE_WINDOW_SYSTEM_H
+#define _LUMINA_NATIVE_WINDOW_SYSTEM_H
+
+#include "NativeWindow.h"
+
+class NativeWindowSystem : public QObject{
+ Q_OBJECT
+private:
+ QList<NativeWindow*> NWindows;
+ QList<NativeWindow*> TWindows;
+
+ //Simplifications to find an already-created window object
+ NativeWindow* findWindow(WId id){
+ for(int i=0; i<NWindows.length(); i++){
+ if(id==NWindows[i]->id()){ return NWindows[i]; }
+ }
+ }
+
+ NativeWindow* findTrayWindow(WId id){
+ for(int i=0; i<TWindows.length(); i++){
+ if(id==TWindows[i]->id()){ return TWindows[i]; }
+ }
+ }
+
+ //Now define a simple private_objects class so that each implementation
+ // has a storage container for placing private objects as needed
+ class p_objects;
+ p_objects* obj;
+
+ // Since some properties may be easier to update in bulk
+ // let the native system interaction do them in whatever logical groups are best
+ void UpdateWindowProperties(NativeWindow* win, QList< NativeWindow::Property > props);
+
+public:
+ NativeWindowSystem();
+ ~NativeWindowSystem();
+
+ //Overarching start/stop functions
+ bool start();
+ void stop();
+
+ //General-purpose listing functions
+ QList<NativeWindow*> currentWindows(){ return NWindows; }
+
+public slots:
+ //These are the slots which are typically only used by the desktop system itself or the NativeWindowEventFilter
+
+ //RootWindow interactions
+ void RegisterVirtualRoot(WId);
+ //void GoToWorkspace(int);
+ //void RegisterWorkspaces(QStringList); //Names of workspaces, in ascending order
+ //void RegisterKnownInteractions();
+
+
+ //NativeWindowEventFilter interactions
+ void NewWindowDetected(WId); //will automatically create the new NativeWindow object
+ void WindowCloseDetected(WId); //will update the lists and make changes if needed
+ void WindowPropertyChanged(WId, NativeWindow::Property); //will rescan the window and update the object as needed
+ void NewKeyPress(int keycode);
+ void NewKeyRelease(int keycode);
+ void NewMousePress(int buttoncode);
+ void NewMouseRelease(int buttoncode);
+ void CheckDamageID(WId);
+
+private slots:
+ //These are the slots which are built-in and automatically connected when a new NativeWindow is created
+ void RequestActivate(WId);
+ void RequestClose(WId);
+ void RequestSetVisible(WId, bool);
+ void RequestSetGeometry(WId, QRect);
+ void RequestSetFrameExtents(WId, QList<int>); //[Left,Right,Top,Bottom] in pixels
+
+signals:
+ void NewWindowAvailable(NativeWindow*);
+ void NewInputEvent(); //a mouse or keypress was detected (lock-state independent);
+ void NewKeyPress(int); //only emitted if lockstate = false
+ void NewKeyRelease(int); //only emitted if lockstate = false
+ void NewMousePress(Qt::MouseButton); //only emitted if lockstate = false
+
+};
+
+#endif
diff --git a/src-qt5/core/libLumina/RootSubWindow.cpp b/src-qt5/core/libLumina/RootSubWindow.cpp
new file mode 100644
index 00000000..7be89f48
--- /dev/null
+++ b/src-qt5/core/libLumina/RootSubWindow.cpp
@@ -0,0 +1,110 @@
+//===========================================
+// Lumina Desktop source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "RootSubWindow.h"
+#include <QDebug>
+
+// === PUBLIC ===
+RootSubWindow::RootSubWindow(QMdiArea *root, NativeWindow *win) : QMdiSubWindow(0){
+ this->setAttribute(Qt::WA_DeleteOnClose);
+ //Create the QWindow and QWidget containers for the window
+ WIN = win;
+ closing = false;
+ WinWidget = QWidget::createWindowContainer( WIN->window(), this);
+ this->setWidget(WinWidget);
+ LoadProperties( QList< NativeWindow::Property>() << NativeWindow::WindowFlags << NativeWindow::Title << NativeWindow::Icon \
+ << NativeWindow::MinSize << NativeWindow::MaxSize << NativeWindow::Size );
+ //Hookup the signals/slots
+ connect(this, SIGNAL(aboutToActivate()), this, SLOT(aboutToActivate()) );
+ connect(WIN, SIGNAL(PropertyChanged(NativeWindow::Property, QVariant)), this, SLOT(propertyChanged(NativeWindow::Property, QVariant)));
+ //Now add this window to the root QMdiArea
+ root->addSubWindow(this);
+ //Make sure the visibily property only gets loaded after it is added to the root area
+ propertyChanged(NativeWindow::Visible, WIN->property(NativeWindow::Visible));
+}
+
+RootSubWindow::~RootSubWindow(){
+
+}
+
+WId RootSubWindow::id(){
+ return WIN->id();
+}
+
+// === PRIVATE ===
+void RootSubWindow::LoadProperties( QList< NativeWindow::Property> list){
+ for(int i=0; i<list.length(); i++){
+ propertyChanged( list[i], WIN->property(list[i]) );
+ }
+}
+
+// === PUBLIC SLOTS ===
+void RootSubWindow::clientClosed(){
+ qDebug() << "Client Closed";
+ closing = true;
+ this->close();
+}
+
+void RootSubWindow::clientHidden(){
+ qDebug() << "Client Hidden";
+ this->hide();
+}
+
+void RootSubWindow::clientShown(){
+ qDebug() << "Client Shown";
+ this->show();
+}
+
+// === PRIVATE SLOTS ===
+void RootSubWindow::aboutToActivate(){
+ WIN->emit RequestActivate(WIN->id());
+}
+
+void RootSubWindow::propertyChanged(NativeWindow::Property prop, QVariant val){
+ if(val.isNull()){ return; } //not the same as a default/empty value - the property has just not been set yet
+ qDebug() << "Set Window Property:" << prop << val;
+ switch(prop){
+ case NativeWindow::Visible:
+ if(val.toBool()){ clientShown(); }
+ else{ clientHidden(); }
+ break;
+ case NativeWindow::Title:
+ this->setWindowTitle(val.toString());
+ break;
+ case NativeWindow::Icon:
+ this->setWindowIcon(val.value< QIcon>());
+ break;
+ case NativeWindow::Size:
+ this->resize(val.toSize());
+ break;
+ case NativeWindow::MinSize:
+ this->setMinimumSize(val.toSize());
+ break;
+ case NativeWindow::MaxSize:
+ this->setMaximumSize(val.toSize());
+ break;
+ case NativeWindow::Active:
+ if(val.toBool()){ this->mdiArea()->setActiveSubWindow(this); }
+ break;
+ case NativeWindow::WindowFlags:
+ this->setWindowFlags( val.value< Qt::WindowFlags >() );
+ break;
+ default:
+ qDebug() << "Window Property Unused:" << prop << val;
+ }
+}
+
+// === PROTECTED ===
+void RootSubWindow::closeEvent(QCloseEvent *ev){
+ if(!closing){
+ //qDebug() << "Close Window By Button:" << WIN->id();
+ ev->ignore();
+ WIN->emit RequestClose(WIN->id());
+ }else{
+ QMdiSubWindow::closeEvent(ev);
+ }
+
+}
diff --git a/src-qt5/core/libLumina/RootSubWindow.h b/src-qt5/core/libLumina/RootSubWindow.h
new file mode 100644
index 00000000..c56f3c96
--- /dev/null
+++ b/src-qt5/core/libLumina/RootSubWindow.h
@@ -0,0 +1,51 @@
+//===========================================
+// Lumina Desktop source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+// This class embeds a native window
+// within the RootWindow area
+//===========================================
+#ifndef _LUMINA_ROOT_WINDOW_SUB_WINDOW_H
+#define _LUMINA_ROOT_WINDOW_SUB_WINDOW_H
+
+#include <QMdiArea>
+#include <QMdiSubWindow>
+#include <QWindow>
+#include <QWidget>
+#include <QCloseEvent>
+
+#include <NativeWindow.h>
+
+class RootSubWindow : public QMdiSubWindow{
+ Q_OBJECT
+public:
+ RootSubWindow(QMdiArea *root, NativeWindow *win);
+ ~RootSubWindow();
+
+ WId id();
+
+private:
+ NativeWindow *WIN;
+ QWidget *WinWidget;
+ bool closing;
+
+ void LoadProperties( QList< NativeWindow::Property> list);
+
+public slots:
+ void clientClosed();
+
+private slots:
+ void clientHidden();
+ void clientShown();
+ void aboutToActivate();
+ void propertyChanged(NativeWindow::Property, QVariant);
+
+
+protected:
+ void closeEvent(QCloseEvent*);
+
+};
+
+#endif
diff --git a/src-qt5/core/libLumina/RootWindow.cpp b/src-qt5/core/libLumina/RootWindow.cpp
index aa5957b5..0758653b 100644
--- a/src-qt5/core/libLumina/RootWindow.cpp
+++ b/src-qt5/core/libLumina/RootWindow.cpp
@@ -11,7 +11,7 @@
#include <QDebug>
// === PUBLIC ===
-RootWindow::RootWindow() : QWidget(0, Qt::Window | Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint){
+RootWindow::RootWindow() : QMdiArea(0){ //QWidget(0, Qt::Window | Qt::BypassWindowManagerHint | Qt::WindowStaysOnBottomHint){
qRegisterMetaType<WId>("WId");
autoResizeTimer = 0;
}
@@ -166,13 +166,32 @@ void RootWindow::ChangeWallpaper(QString id, RootWindow::ScaleType scale, QStrin
}
+void RootWindow::NewWindow(NativeWindow *win){
+ RootSubWindow *subwin = 0;
+ for(int i=0; i<WINDOWS.length() && subwin==0; i++){
+ if(WINDOWS[i]->id() == win->id()){ subwin = WINDOWS[i]; }
+ }
+ if(subwin==0){
+ subwin = new RootSubWindow(this, win);
+ connect(win, SIGNAL(WindowClosed(WId)), this, SLOT(CloseWindow(WId)) );
+ WINDOWS << subwin;
+ }
+ //subwin->show();
+}
+
+void RootWindow::CloseWindow(WId win){
+ for(int i=0; i<WINDOWS.length(); i++){
+ if(WINDOWS[i]->id() == win){ WINDOWS.takeAt(i)->clientClosed(); break; }
+ }
+}
+
// === PRIVATE SLOTS ===
// === PROTECTED ===
void RootWindow::paintEvent(QPaintEvent *ev){
//qDebug() << "RootWindow: PaintEvent:" << ev->rect(); //<< QDateTime::currentDateTime()->toString(QDateTime::ShortDate);
bool found = false;
- QPainter painter(this);
+ QPainter painter(this->viewport());
for(int i=0; i<WALLPAPERS.length(); i++){
if(WALLPAPERS[i].area.intersects(ev->rect()) ){
found = true;
diff --git a/src-qt5/core/libLumina/RootWindow.h b/src-qt5/core/libLumina/RootWindow.h
index b371d239..5d3bc963 100644
--- a/src-qt5/core/libLumina/RootWindow.h
+++ b/src-qt5/core/libLumina/RootWindow.h
@@ -18,8 +18,12 @@
#include <QTimer>
#include <QApplication>
#include <QPaintEvent>
+#include <QMdiArea>
-class RootWindow : public QWidget{
+#include "RootSubWindow.h"
+#include "NativeWindow.h"
+
+class RootWindow : public QMdiArea{
Q_OBJECT
public:
enum ScaleType{ SolidColor, Stretch, Full, Fit, Center, Tile, BottomLeft, BottomRight, BottomCenter, \
@@ -43,11 +47,17 @@ private:
QList<screeninfo> WALLPAPERS;
void updateScreenPixmap(screeninfo *info); //used for recalculating the wallpaper pixmap based on file/area/scale as needed
+ //Window Management
+ QList<RootSubWindow*> WINDOWS;
+
public slots:
void ResizeRoot();
void ChangeWallpaper(QString id, RootWindow::ScaleType scale, QString file);
//Note: for "SingleColor" scaling the "file" variable should be "rgb(R,G,B)" or "#hexcode"
+ void NewWindow(NativeWindow*);
+ void CloseWindow(WId); //automatically connected for any new native window
+
private slots:
protected:
diff --git a/src-qt5/core/libLumina/RootWindow.pri b/src-qt5/core/libLumina/RootWindow.pri
index 7ef3efb0..35e0e770 100644
--- a/src-qt5/core/libLumina/RootWindow.pri
+++ b/src-qt5/core/libLumina/RootWindow.pri
@@ -1,9 +1,13 @@
# Files
-SOURCES *= $${PWD}/RootWindow.cpp
-HEADERS *= $${PWD}/RootWindow.h
+SOURCES *= $${PWD}/RootWindow.cpp \
+ $${PWD}/RootSubWindow.cpp
+
+HEADERS *= $${PWD}/RootWindow.h \
+ $${PWD}/RootSubWindow.h
INCLUDEPATH *= ${PWD}
-# include LUtils and LuminaX11
+# include other library dependencies
include(LUtils.pri)
+include(NativeWindow.pri);
diff --git a/src-qt5/core/libLumina/test/main.cpp b/src-qt5/core/libLumina/test/main.cpp
new file mode 100644
index 00000000..309fb938
--- /dev/null
+++ b/src-qt5/core/libLumina/test/main.cpp
@@ -0,0 +1,13 @@
+
+#include "../LuminaRandR.h"
+#include <QDebug>
+#include <QApplication>
+
+int main(int argc, char** argv){
+ QApplication A(argc, argv);
+ qDebug() << "Starting monitor scan...";
+ QList<OutputDevice> outputs = OutputDevice::availableMonitors();
+ qDebug() << "Finished monitor Scan";
+ OutputDeviceList();
+ return 0;
+}
diff --git a/src-qt5/core/libLumina/test/test.pro b/src-qt5/core/libLumina/test/test.pro
new file mode 100644
index 00000000..9674801b
--- /dev/null
+++ b/src-qt5/core/libLumina/test/test.pro
@@ -0,0 +1,7 @@
+QT = core gui widgets
+
+TARGET = test
+
+SOURCES += main.cpp
+
+include(../LuminaRandR.pri)
bgstack15