diff options
-rw-r--r-- | src-qt5/core/libLumina/LuminaRandR-X11.cpp | 171 | ||||
-rw-r--r-- | src-qt5/core/libLumina/LuminaRandR.h | 60 | ||||
-rw-r--r-- | src-qt5/core/libLumina/test/main.cpp | 15 |
3 files changed, 191 insertions, 55 deletions
diff --git a/src-qt5/core/libLumina/LuminaRandR-X11.cpp b/src-qt5/core/libLumina/LuminaRandR-X11.cpp index 85251b64..f8907741 100644 --- a/src-qt5/core/libLumina/LuminaRandR-X11.cpp +++ b/src-qt5/core/libLumina/LuminaRandR-X11.cpp @@ -6,13 +6,13 @@ //=========================================== #include "LuminaRandR.h" -#include "xcb/randr.h" -#include "xcb/xcb_atom.h" +//#include "xcb/randr.h" +//#include "xcb/xcb_atom.h" #include <QDebug> #include <QX11Info> -static QString atomToName(xcb_atom_t atom){ +inline 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); @@ -20,7 +20,7 @@ static QString atomToName(xcb_atom_t atom){ }; //More efficient method for converting lots of atoms to strings -static QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ +inline QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ //qDebug() << "atomsToNames:" << num; QList< xcb_get_atom_name_cookie_t > cookies; //qDebug() << " - Get cookies"; @@ -36,12 +36,25 @@ static QStringList atomsToNames(xcb_atom_t *atoms, unsigned int num){ return names; }; -class OutputDevice::p_objects{ +/*class OutputDevice::p_objects{ public: - xcb_atom_t monitor_atom; - QList<xcb_randr_output_t> outputs; //the actual output devices used by the monitor + xcb_atom_t monitor_atom; //This is the index used to identify particular monitors (unique ID) -}; + //Cached Information + bool primary, automatic; + QRect geometry; + QList<QSize> resolutions; + QSize physicalSizeMM; + QString name; + QList<xcb_randr_output_t> outputs; + + p_objects(){ + // Set the defaults for non-default-constructed variables + primary = automatic = false; + monitor_atom = 0; + } + +};*/ //Global Listing of Devices QList<OutputDevice> OutputDevice::availableMonitors(){ @@ -80,30 +93,44 @@ QList<OutputDevice> OutputDevice::availableMonitors(){ } //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(QString id){ + //p_obj = new p_objects(); + p_obj.name = id; + p_obj.primary = p_obj.automatic = false; + p_obj.monitor_atom = 0; + updateInfoCache(); } OutputDevice::~OutputDevice(){ - + //delete p_obj; } +// INFORMATION FUNCTIONS (simply read from cache) +QString OutputDevice::ID(){ qDebug() << "Find ID"; return p_obj.name; } +bool OutputDevice::isEnabled(){ return p_obj.monitor_atom !=0; } +bool OutputDevice::isPrimary(){ return p_obj.primary; } +bool OutputDevice::isAutomatic(){ return p_obj.automatic; } +QList<QSize> OutputDevice::availableResolutions(){ return p_obj.resolutions; } +QSize OutputDevice::currentResolution(){ return p_obj.geometry.size(); } //no concept of panning/scaling yet +QRect OutputDevice::currentGeometry(){ return p_obj.geometry; } + //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; +bool OutputDevice::setAsPrimary(bool set){ + if(p_obj.primary == set){ return true; } //no change needed + bool ok = false; + for(int i=0; i<p_obj.outputs.length(); i++){ + if(set){ xcb_randr_set_output_primary (QX11Info::connection(), QX11Info::appRootWindow(), p_obj.outputs[i]); } + p_obj.primary = set; //Only need to push a "set" primary up through XCB - will automatically deactivate the other monitors + ok = true; + break; } - return isPrimary; + return ok; } 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; + 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; @@ -111,7 +138,7 @@ bool OutputDevice::disable(){ 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; } + if(p_obj.monitor_atom!=0){ return; } qDebug() << "Enable Monitor:" << geom; } @@ -120,7 +147,86 @@ void OutputDevice::changeResolution(QSize){ } +void OutputDevice::updateInfoCache(){ + //Find the **active** monitor with the given id/name + if(p_obj.monitor_atom !=0 || !p_obj.name.isEmpty() ){ + 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){ + 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() << " Index:" << iter.index << "Rem:" << iter.rem; + if( p_obj.monitor_atom == iter.data->name || p_obj.name == atomToName(iter.data->name) ){ + if(p_obj.monitor_atom == 0){ p_obj.monitor_atom = iter.data->name; } + if(p_obj.name.isEmpty()){ p_obj.name = atomToName(iter.data->name); } + //Now update all the info in the cache + p_obj.primary = (iter.data->primary == 1); + p_obj.automatic = (iter.data->automatic == 1); + p_obj.geometry = QRect(iter.data->x, iter.data->y, iter.data->width, iter.data->height); + p_obj.physicalSizeMM = QSize(iter.data->width_in_millimeters, iter.data->height_in_millimeters); + //Load the "outputs" + p_obj.outputs.clear(); + int out_len = xcb_randr_monitor_info_outputs_length(iter.data); + for(int i=0; i<out_len; i++){ p_obj.outputs << xcb_randr_monitor_info_outputs(iter.data)[i]; } + qDebug() << "Info Loaded:" << p_obj.name; + //break; //Finished with the information for this particular monitor + } + xcb_randr_monitor_info_next(&iter); + } + free(reply); + } //end check for reply structure + } //end loading of active/enabled monitor information + + //Now load any information from the outputs + for(int i=0; i<p_obj.outputs.length(); i++){ + xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(QX11Info::connection(), + xcb_randr_get_output_info_unchecked(QX11Info::connection(), p_obj.outputs[i], QX11Info::appTime()), + NULL); + if(info==0){ continue; } //bad output + //Modes + int mode_len = xcb_randr_get_output_info_modes_length(info); + qDebug() << "Number of Modes:" << mode_len; + if(mode_len<=0){ continue; } //skip this output - not a physical screen which can be used + p_obj.resolutions.clear(); + for(int j=0; j<mode_len; j++){ + xcb_randr_mode_t mode = xcb_randr_get_output_info_modes(info)[j]; + //Still need to convert the mode into the resolution somehow + p_obj.resolutions << QSize(mode,1); + } + } + +} + +// ============================ +// OutputDeviceList +// ============================ + OutputDeviceList::OutputDeviceList(){ + + QList<xcb_randr_output_t> usedOutputs; + //Get the information about all the "enabled" monitors + xcb_randr_get_monitors_cookie_t cookieA = xcb_randr_get_monitors_unchecked(QX11Info::connection(), QX11Info::appRootWindow(), 1); + xcb_randr_get_monitors_reply_t *replyA = xcb_randr_get_monitors_reply(QX11Info::connection(), cookieA, NULL); + if(replyA!=0){ + xcb_randr_monitor_info_iterator_t iter = xcb_randr_get_monitors_monitors_iterator(replyA); + //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); + OutputDevice dev(name); + usedOutputs << dev.p_obj.outputs; + + this->append(dev); //add to the internal list + xcb_randr_monitor_info_next(&iter); + } + //Free up any objects we are done with + free(replyA); + } //end loading of active/enabled monitors + +/* + //Now get the information about any **UNUSED** monitors/outputs 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); @@ -132,12 +238,9 @@ OutputDeviceList::OutputDeviceList(){ 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() << " -- Mode:" << mode.id; + qDebug() << " - Size Option:" << 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 @@ -147,7 +250,9 @@ OutputDeviceList::OutputDeviceList(){ qDebug() << "==== Output Information #"+QString::number(i); //Modes - qDebug() << "Number of Modes:" << xcb_randr_get_output_info_modes_length(info); + int mode_len = xcb_randr_get_output_info_modes_length(info); + qDebug() << "Number of Modes:" << mode_len; + if(mode_len<=0){ continue; } //skip this output - not a physical screen which can be used //Clones @@ -155,7 +260,7 @@ OutputDeviceList::OutputDeviceList(){ //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); + 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; @@ -176,10 +281,6 @@ OutputDeviceList::OutputDeviceList(){ 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; @@ -189,7 +290,7 @@ OutputDeviceList::OutputDeviceList(){ free(info); } - free(reply); + free(reply);*/ } OutputDeviceList::~OutputDeviceList(){ diff --git a/src-qt5/core/libLumina/LuminaRandR.h b/src-qt5/core/libLumina/LuminaRandR.h index 448c676d..86c713db 100644 --- a/src-qt5/core/libLumina/LuminaRandR.h +++ b/src-qt5/core/libLumina/LuminaRandR.h @@ -17,17 +17,34 @@ #include <QRect> #include <QList> +// XCB +#include "xcb/randr.h" +#include "xcb/xcb_atom.h" + +struct p_objects{ +//public: + xcb_atom_t monitor_atom; //This is the index used to identify particular monitors (unique ID) + + //Cached Information + bool primary, automatic; + QRect geometry; + QList<QSize> resolutions; + QSize physicalSizeMM; + QString name; + QList<xcb_randr_output_t> outputs; + + /*p_objects(){ + // Set the defaults for non-default-constructed variables + primary = automatic = false; + monitor_atom = 0; + }*/ + +}; 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 + + // EXPANSIONS TO-DO //Refresh Rate //int cHz; //current refresh rate //QList<int> availHz; //available refresh rates @@ -39,19 +56,32 @@ public: static QList<OutputDevice> availableMonitors(); //FUNCTIONS (do not use directly - use the static list function instead) - OutputDevice(); + OutputDevice(QString id); ~OutputDevice(); + //Information + QString ID(); + + bool isEnabled(); + bool isPrimary(); + bool isAutomatic(); + QList<QSize> availableResolutions(); + QSize currentResolution(); //could be different from geometry.size() if things like panning/rotation are enabled + QRect currentGeometry(); + //Modification - bool setAsPrimary(); + bool setAsPrimary(bool); bool disable(); void enable(QRect geom = QRect()); //if no geom provided, will add as the right-most screen at optimal resolution void changeResolution(QSize); - + void changeGeometry(QRect); //move a currently-enabled screen to another place + + void updateInfoCache(); //Run this after all modification functions to refresh the current info for this device + //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; + // has a storage container for placing semi-private objects as needed + //class p_objects; //forward declaration - defined in the .cpp file + p_objects p_obj; }; class OutputDeviceList : public QList<OutputDevice>{ @@ -64,7 +94,5 @@ public: void disableMonitor(QString id); //void enableMonitor(QString id, -private: - }; #endif diff --git a/src-qt5/core/libLumina/test/main.cpp b/src-qt5/core/libLumina/test/main.cpp index 309fb938..b2ec9e41 100644 --- a/src-qt5/core/libLumina/test/main.cpp +++ b/src-qt5/core/libLumina/test/main.cpp @@ -5,9 +5,16 @@ int main(int argc, char** argv){ QApplication A(argc, argv); - qDebug() << "Starting monitor scan..."; - QList<OutputDevice> outputs = OutputDevice::availableMonitors(); - qDebug() << "Finished monitor Scan"; - OutputDeviceList(); + qDebug() << "Load Monitor Device Information"; + OutputDeviceList devList; + qDebug() << "Detected Information:"; + for(int i=0; i<devList.length(); i++){ + qDebug() << "["+devList[i].ID()+"]"; + qDebug() << " - isEnabled:" << devList[i].isEnabled(); + qDebug() << " - isPrimary:" << devList[i].isPrimary(); + qDebug() << " - isAutomatic:" << devList[i].isAutomatic(); + qDebug() << " - Current Geometry:" << devList[i].currentGeometry(); + qDebug() << " - Available Resolutions:" << devList[i].availableResolutions(); + } return 0; } |