//=========================================== // Lumina-DE source code // Copyright (c) 2015, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include "MainUI.h" #include "ui_MainUI.h" #include <LuminaXDG.h> #include <LUtils.h> #include <QTimer> MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){ ui->setupUi(this); loadIcons(); //Fill the location list with the valid entries ui->combo_location->clear(); ui->combo_location->addItem(tr("Right Of"), "--right-of"); ui->combo_location->addItem(tr("Left Of"), "--left-of"); connect(ui->push_close, SIGNAL(clicked()), this, SLOT(close()) ); connect(ui->push_rescan, SIGNAL(clicked()), this, SLOT(UpdateScreens()) ); connect(ui->push_activate, SIGNAL(clicked()), this, SLOT(ActivateScreen()) ); connect(ui->tool_deactivate, SIGNAL(clicked()), this, SLOT(DeactivateScreen()) ); connect(ui->tool_moveleft, SIGNAL(clicked()), this, SLOT(MoveScreenLeft()) ); connect(ui->tool_moveright, SIGNAL(clicked()), this, SLOT(MoveScreenRight()) ); connect(ui->tool_applyconfig, SIGNAL(clicked()), this, SLOT(ApplyChanges()) ); connect(ui->list_screens, SIGNAL(itemSelectionChanged()),this, SLOT(ScreenSelected()) ); QTimer::singleShot(0, this, SLOT(UpdateScreens()) ); } MainUI::~MainUI(){ } void MainUI::loadIcons(){ this->setWindowIcon( LXDG::findIcon("preferences-system-windows-actions","") ); ui->tool_deactivate->setIcon( LXDG::findIcon("list-remove","") ); ui->tool_moveleft->setIcon( LXDG::findIcon("arrow-left","") ); ui->tool_moveright->setIcon( LXDG::findIcon("arrow-right","") ); ui->push_activate->setIcon( LXDG::findIcon("list-add","") ); ui->push_rescan->setIcon( LXDG::findIcon("view-refresh","") ); ui->push_close->setIcon( LXDG::findIcon("window-close","") ); ui->tabWidget->setTabIcon(0, LXDG::findIcon("preferences-desktop-display","") ); ui->tabWidget->setTabIcon(1, LXDG::findIcon("list-add","") ); ui->tool_applyconfig->setIcon( LXDG::findIcon("dialog-ok-apply","") ); } QStringList MainUI::currentOpts(){ //Read all the settings and create the xrandr options to maintain these settings QStringList opts; for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].order <0){ continue; } //skip this screen - non-active opts << "--output" << SCREENS[i].ID << "--mode" << QString::number(SCREENS[i].geom.width())+"x"+QString::number(SCREENS[i].geom.height()); if(SCREENS[i].isprimary){ opts << "--primary"; } if(SCREENS[i].order > 0){ //Get the ID of the previous screen QString id; for(int j=0; j<SCREENS.length(); j++){ if(SCREENS[j].order == SCREENS[i].order-1){ id = SCREENS[j].ID; break;} } if(!id.isEmpty()){ opts << "--right-of" << id; } } } return opts; } ScreenInfo MainUI::currentScreenInfo(){ QListWidgetItem *item = ui->list_screens->currentItem(); if(item!=0){ for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].ID==item->whatsThis()){ return SCREENS[i]; } } } //Fallback when nothing found/selected return ScreenInfo(); } void MainUI::UpdateScreens(){ //First probe the server for current screens SCREENS = RRSettings::CurrentScreens(); /*QStringList info = LUtils::getCmdOutput("xrandr -q"); ScreenInfo cscreen; for(int i=0; i<info.length(); i++){ if(info[i].contains("connected") ){ //qDebug() << "xrandr info:" << info[i]; if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; //current screen finished - save it into the array cscreen = ScreenInfo(); //Now create a new structure } //qDebug() << "Line:" << info[i]; QString dev = info[i].section(" ",0,0); //device ID //The device resolution can be either the 3rd or 4th output - check both QString devres = info[i].section(" ",2,2, QString::SectionSkipEmpty); if(!devres.contains("x")){ devres = info[i].section(" ",3,3,QString::SectionSkipEmpty); } if(!devres.contains("x")){ devres.clear(); } qDebug() << " - ID:" <<dev << "Current Geometry:" << devres; //qDebug() << " - Res:" << devres; if( !devres.contains("x") || !devres.contains("+") ){ devres.clear(); } //qDebug() << " - Res (modified):" << devres; if(info[i].contains(" disconnected ") && !devres.isEmpty() ){ //Disable this device and restart (disconnected, but still attached to the X server) DeactivateScreen(dev); UpdateScreens(); return; }else if( !devres.isEmpty() ){ cscreen.isprimary = info[i].contains(" primary "); //Device that is connected and attached (has a resolution) qDebug() << "Create new Screen entry:" << dev << devres; cscreen.ID = dev; //Note: devres format: "<width>x<height>+<xoffset>+<yoffset>" cscreen.geom.setRect( devres.section("+",-2,-2).toInt(), devres.section("+",-1,-1).toInt(), devres.section("x",0,0).toInt(), devres.section("+",0,0).section("x",1,1).toInt() ); }else if(info[i].contains(" connected")){ //Device that is connected, but not attached qDebug() << "Create new Screen entry:" << dev << "none"; cscreen.ID = dev; cscreen.order = -2; //flag this right now as a non-active screen } }else if( !cscreen.ID.isEmpty() && info[i].section("\t",0,0,QString::SectionSkipEmpty).contains("x")){ //available resolution for a device cscreen.resList << info[i].section("\t",0,0,QString::SectionSkipEmpty); } } //end loop over info lines if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; } //make sure to add the last screen to the array */ //Now go through the screens and arrange them in order from left->right in the UI bool found = true; int xoffset = 0; //start at 0 int cnum = 0; QString csel = ""; if(ui->list_screens->currentItem()!=0){ csel = ui->list_screens->currentItem()->whatsThis(); } ui->list_screens->clear(); while(found){ found = false; //make sure to break out if a screen is not found for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].order != -1){} //already evaluated - skip it else if(SCREENS[i].geom.x()==xoffset){ found = true; //make sure to look for the next one xoffset = xoffset+SCREENS[i].geom.width(); //next number to look for SCREENS[i].order = cnum; //assign the current order to it cnum++; //get ready for the next one QListWidgetItem *it = new QListWidgetItem(); it->setTextAlignment(Qt::AlignCenter); it->setText( SCREENS[i].ID+"\n ("+QString::number(SCREENS[i].geom.width())+"x"+QString::number(SCREENS[i].geom.height())+") " ); it->setWhatsThis(SCREENS[i].ID); ui->list_screens->addItem(it); if(SCREENS[i].ID==csel){ ui->list_screens->setCurrentItem(it); } } } } //Now update the available/current screens in the UI ui->combo_availscreens->clear(); ui->combo_cscreens->clear(); for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].order<0){ ui->combo_availscreens->addItem(SCREENS[i].ID); }else{ ui->combo_cscreens->addItem(SCREENS[i].ID); } } if(ui->combo_availscreens->count()<1){ ui->group_avail->setVisible(false); ui->tabWidget->setCurrentIndex(0); ui->tabWidget->setTabEnabled(1,false); }else{ ui->group_avail->setVisible(true); ui->tabWidget->setTabEnabled(1,true); } if(ui->list_screens->currentItem()==0){ ui->list_screens->setCurrentRow(0); } ScreenSelected(); //update buttons RRSettings::SaveScreens(SCREENS); } void MainUI::ScreenSelected(){ QListWidgetItem *item = ui->list_screens->currentItem(); if(item==0){ //nothing selected ui->tool_deactivate->setEnabled(false); ui->tool_moveleft->setEnabled(false); ui->tool_moveright->setEnabled(false); ui->tab_config->setEnabled(false); }else{ //Item selected ui->tool_deactivate->setEnabled(ui->list_screens->count()>1); ui->tool_moveleft->setEnabled(ui->list_screens->row(item) > 0); ui->tool_moveright->setEnabled(ui->list_screens->row(item) < (ui->list_screens->count()-1)); ui->tab_config->setEnabled(true); //Update the info available on the config tab ScreenInfo cur = currentScreenInfo(); ui->combo_resolution->clear(); QString cres = QString::number(cur.geom.width())+"x"+QString::number(cur.geom.height()); for(int i=0; i<cur.resList.length(); i++){ QString res = cur.resList[i].section(" ",0,0, QString::SectionSkipEmpty); if(cur.resList[i].contains("+")){ ui->combo_resolution->addItem( QString(tr("%1 (Recommended)")).arg(res), res); } else{ui->combo_resolution->addItem(res, res); } if(cur.resList[i].contains(cres)){ ui->combo_resolution->setCurrentIndex(i); } } ui->check_primary->setChecked( cur.isprimary ); } } void MainUI::MoveScreenLeft(){ QListWidgetItem *item = ui->list_screens->currentItem(); if(item==0){ return; } //no selection //Get the current ID QString CID = item->whatsThis(); //Now get the ID of the one on the left item = ui->list_screens->item( ui->list_screens->row(item)-1 ); if(item == 0){ return; } //no item on the left (can't go left) QString LID = item->whatsThis(); //left ID //Adjust the order of the two screens for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].ID == CID){ SCREENS[i].order = SCREENS[i].order-1; } else if(SCREENS[i].ID==LID){ SCREENS[i].order = SCREENS[i].order+1; } } //Now run the command QStringList opts = currentOpts(); LUtils::runCmd("xrandr", opts); //Now run the command //LUtils::runCmd("xrandr", QStringList() << "--output" << CID << "--left-of" << LID); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); } void MainUI::MoveScreenRight(){ QListWidgetItem *item = ui->list_screens->currentItem(); if(item==0){ return; } //no selection //Get the current ID QString CID = item->whatsThis(); //Now get the ID of the one on the left item = ui->list_screens->item( ui->list_screens->row(item)+1 ); if(item == 0){ return; } //no item on the right (can't go right) QString RID = item->whatsThis(); //right ID //Adjust the order of the two screens for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].ID == RID){ SCREENS[i].order = SCREENS[i].order-1; } else if(SCREENS[i].ID==CID){ SCREENS[i].order = SCREENS[i].order+1; } } //Now run the command QStringList opts = currentOpts(); LUtils::runCmd("xrandr", opts); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); } void MainUI::DeactivateScreen(QString device){ if(device.isEmpty()){ //Get the currently selected device QListWidgetItem *item = ui->list_screens->currentItem(); if(item==0){ return; } //no selection //Get the current ID device = item->whatsThis(); } if(device.isEmpty()){ return; } //nothing found //Remove the screen from the settings for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].ID==device){ SCREENS.removeAt(i); break; } } //Now run the command QStringList opts = currentOpts(); opts << "--output" << device << "--off"; LUtils::runCmd("xrandr", opts); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); } void MainUI::ActivateScreen(){ //Assemble the command; QString ID = ui->combo_availscreens->currentText(); QString DID = ui->combo_cscreens->currentText(); QString loc = ui->combo_location->currentData().toString(); if(ID.isEmpty() || DID.isEmpty() || loc.isEmpty()){ return; } //invalid inputs QStringList opts = currentOpts(); opts << "--output" << ID << loc << DID <<"--auto"; //qDebug() << "Activate Options:" << opts; LUtils::runCmd("xrandr", opts ); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); } void MainUI::ApplyChanges(){ //NOTE: need to re-specifiy the QListWidgetItem *it = ui->list_screens->currentItem(); if(it==0){ return; } //nothing to do QString newres = ui->combo_resolution->currentData().toString(); if(newres.isEmpty()){ return; } //nothing to do //qDebug() << "Apply Screen Changes" << it->whatsThis() << "->" << newres; //Adjust the order of the two screens bool setprimary = ui->check_primary->isChecked(); for(int i=0; i<SCREENS.length(); i++){ if(SCREENS[i].ID == it->whatsThis()){ SCREENS[i].geom.setWidth(newres.section("x",0,0).toInt()); SCREENS[i].geom.setHeight(newres.section("x",1,1).toInt()); } if(setprimary){ SCREENS[i].isprimary = SCREENS[i].ID==it->whatsThis(); } } //Now run the command QStringList opts = currentOpts(); LUtils::runCmd("xrandr", opts); QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); }