diff options
author | Weblate <noreply@weblate.org> | 2017-08-17 16:04:15 +0000 |
---|---|---|
committer | Weblate <noreply@weblate.org> | 2017-08-17 16:04:15 +0000 |
commit | da678fc7fa150351ce15acf8fed2c90dde244db7 (patch) | |
tree | 8c5702ce54b5e533b61c5a2ce555e5b5bdde1d48 /src-qt5/core-utils/lumina-xconfig | |
parent | Translated using Weblate (French) (diff) | |
parent | Merge remote-tracking branch 'origin/master' (diff) | |
download | lumina-da678fc7fa150351ce15acf8fed2c90dde244db7.tar.gz lumina-da678fc7fa150351ce15acf8fed2c90dde244db7.tar.bz2 lumina-da678fc7fa150351ce15acf8fed2c90dde244db7.zip |
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src-qt5/core-utils/lumina-xconfig')
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/MainUI.cpp | 461 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/MainUI.h | 24 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/MainUI.ui | 193 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp | 101 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/ScreenSettings.h | 13 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/i18n/lumina-xconfig_en_AU.ts | 4 | ||||
-rw-r--r-- | src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro | 1 |
7 files changed, 431 insertions, 366 deletions
diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp index 6553bb37..030b96be 100644 --- a/src-qt5/core-utils/lumina-xconfig/MainUI.cpp +++ b/src-qt5/core-utils/lumina-xconfig/MainUI.cpp @@ -15,19 +15,34 @@ 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"); + scaleFactor = 1/15.0; //simple default value + ui->combo_rotation->clear(); + ui->combo_rotation->addItem(tr("None"), 0); + ui->combo_rotation->addItem(tr("Left"), -90); + ui->combo_rotation->addItem(tr("Right"), 90); + ui->combo_rotation->addItem(tr("Inverted"), 180); + singleTileMenu = new QMenu(this); + singleTileMenu->addAction(tr("Align Horizontally"))->setWhatsThis("X"); + singleTileMenu->addAction(tr("Align Vertically"))->setWhatsThis("Y"); + singleTileMenu->addAction(tr("Align Horizontal then Vertical"))->setWhatsThis("XY"); + singleTileMenu->addAction(tr("Align Vertical then Horizontal"))->setWhatsThis("YX"); + ui->mdiArea->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->mdiArea, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu()) ); + + connect(singleTileMenu, SIGNAL(triggered(QAction*)), this, SLOT(tileSingleScreen(QAction*)) ); 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_save, SIGNAL(clicked()), this, SLOT(SaveSettings()) ); connect(ui->tool_applyconfig, SIGNAL(clicked()), this, SLOT(ApplyChanges()) ); - connect(ui->list_screens, SIGNAL(itemSelectionChanged()),this, SLOT(ScreenSelected()) ); + connect(ui->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)),this, SLOT(ScreenSelected()) ); + connect(ui->tool_tileX, SIGNAL(clicked()), this, SLOT(tileScreensX()) ); + connect(ui->tool_tileY, SIGNAL(clicked()), this, SLOT(tileScreensY()) ); + connect(ui->tool_tile, SIGNAL(clicked()), this, SLOT(tileScreens()) ); + connect(ui->combo_availscreens, SIGNAL(currentIndexChanged(int)), this, SLOT(updateNewScreenResolutions()) ); QTimer::singleShot(0, this, SLOT(UpdateScreens()) ); } @@ -38,8 +53,7 @@ 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","") ); @@ -48,30 +62,17 @@ void MainUI::loadIcons(){ 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; +QString MainUI::currentSelection(){ + QMdiSubWindow *tmp = ui->mdiArea->activeSubWindow(); + if(tmp!=0){ return tmp->whatsThis(); } + else{ return ""; } } ScreenInfo MainUI::currentScreenInfo(){ - QListWidgetItem *item = ui->list_screens->currentItem(); + QString item = currentSelection(); if(item!=0){ for(int i=0; i<SCREENS.length(); i++){ - if(SCREENS[i].ID==item->whatsThis()){ return SCREENS[i]; } + if(SCREENS[i].ID==item){ return SCREENS[i]; } } } //Fallback when nothing found/selected @@ -79,104 +80,84 @@ ScreenInfo MainUI::currentScreenInfo(){ } void MainUI::AddScreenToWidget(ScreenInfo screen){ - QListWidgetItem *it = new QListWidgetItem(); - it->setTextAlignment(Qt::AlignCenter); - it->setText( screen.ID+"\n\n ("+QString::number(screen.geom.x())+", "+QString::number(screen.geom.y())+")\n ("+QString::number(screen.geom.width())+"x"+QString::number(screen.geom.height())+") " ); + qDebug() << "Add Screen To Widget:" << screen.ID << screen.geom; + QLabel *lab = new QLabel(this); + lab->setAlignment(Qt::AlignCenter); + QMdiSubWindow *it = ui->mdiArea->addSubWindow(lab, Qt::Tool | Qt::CustomizeWindowHint | Qt::WindowTitleHint); + it->setSystemMenu(0); + it->setWindowTitle(screen.ID); + lab->setText(QString::number(screen.geom.width())+"x"+QString::number(screen.geom.height())); + it->setWhatsThis(screen.ID); - ui->list_screens->addItem(it); + QRect scaled( screen.geom.topLeft()*scaleFactor, screen.geom.size()*scaleFactor); + qDebug() << " - Scaled:" << scaled; + it->show(); + it->setGeometry(scaled); //scale it down for the display + it->setFixedSize(scaled.size()); + +} + +void MainUI::SyncBackend(){ + QString item = currentSelection(); + if(item.isEmpty()){ return; } //nothing to do + QString newres = ui->combo_resolution->currentData().toString().section("(",0,0).simplified(); + if(newres.isEmpty()){ return; } //nothing to do + //qDebug() << "Apply Screen Changes" << item << "->" << newres; + //Adjust the order of the two screens + bool setprimary = ui->check_primary->isChecked(); + QList<QMdiSubWindow*> windows = ui->mdiArea->subWindowList(); + for(int i=0; i<SCREENS.length(); i++){ + if(SCREENS[i].ID == item){ + SCREENS[i].geom.setWidth(newres.section("x",0,0).toInt()); + SCREENS[i].geom.setHeight(newres.section("x",1,1).toInt()); + //qDebug() << " - New Geom:" << SCREENS[i].geom; + SCREENS[i].rotation = ui->combo_rotation->currentData().toInt(); + } + if(setprimary){ SCREENS[i].isprimary = (SCREENS[i].ID==item); } + //Find the window associated with this screen + for(int s=0; s<windows.length(); s++){ + if(windows[s]->whatsThis()==SCREENS[i].ID){ + qDebug() << "Adjust geom of window:" << SCREENS[i].geom; + SCREENS[i].geom.moveTopLeft( windows[s]->geometry().topLeft()/scaleFactor ); + qDebug() << " - New Geom:" << SCREENS[i].geom; + if(SCREENS[i].applyChange<1){ SCREENS[i].applyChange = (windows[s]->widget()->isEnabled() ? 0 : 1); } //disabled window is one that will be removed + } + } + } } 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 - */ + //Determine the scale factor for putting these into the UI + QRegion tot; + for(int i=0; i<SCREENS.length(); i++){ + if(SCREENS[i].isactive){ tot = tot.united( SCREENS[i].geom ); } + } + int wid = tot.boundingRect().width(); + scaleFactor = (0.9*ui->mdiArea->width())/wid; //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){qDebug() << "Skip Screen:" << i << SCREENS[i].order; } //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 - AddScreenToWidget(SCREENS[i]); - /*QListWidgetItem *it = new QListWidgetItem(); - it->setTextAlignment(Qt::AlignCenter); - it->setText( SCREENS[i].ID+"\n ("+QString::number(SCREENS[i].geom.x())+", "+QString::number(SCREENS[i].geom.y())+")\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); } - }else if(SCREENS[i].geom.x() < xoffset || SCREENS[i].geom.x() > xoffset){ - //Screen not aligned with previous screen edge - qDebug() << "Found mis-aligned screen:" << i << SCREENS[i].ID; - 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 - AddScreenToWidget(SCREENS[i]); - } - } + //bool found = true; + //int xoffset = 0; //start at 0 + //int cnum = 0; + QString csel = currentSelection(); + //Clear all the current widgets + while(ui->mdiArea->currentSubWindow()!=0 ){ + QMdiSubWindow *tmp = ui->mdiArea->currentSubWindow(); + tmp->widget()->deleteLater(); + ui->mdiArea->removeSubWindow(tmp); + tmp->deleteLater(); + } + //Now add all the active screens to the display + for(int i=0; i<SCREENS.length(); i++){ + if(SCREENS[i].isactive){ AddScreenToWidget(SCREENS[i]); } } //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){ + if(!SCREENS[i].isactive && SCREENS[i].isavailable){ ui->combo_availscreens->addItem(SCREENS[i].ID); - }else{ - ui->combo_cscreens->addItem(SCREENS[i].ID); } } if(ui->combo_availscreens->count()<1){ @@ -187,24 +168,20 @@ void MainUI::UpdateScreens(){ 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); + updateNewScreenResolutions(); } void MainUI::ScreenSelected(){ - QListWidgetItem *item = ui->list_screens->currentItem(); - if(item==0){ + QString item = currentSelection(); + //QListWidgetItem *item = ui->list_screens->currentItem(); + if(item.isEmpty()){ //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->tool_deactivate->setEnabled(true); ui->tab_config->setEnabled(true); //Update the info available on the config tab ScreenInfo cur = currentScreenInfo(); @@ -217,102 +194,190 @@ void MainUI::ScreenSelected(){ if(cur.resList[i].contains(cres)){ ui->combo_resolution->setCurrentIndex(i); } } ui->check_primary->setChecked( cur.isprimary ); + int index = ui->combo_rotation->findData( cur.rotation ); + if(index<0){ index = 0; } + ui->combo_rotation->setCurrentIndex(index); } } -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 +void MainUI::updateNewScreenResolutions(){ + QString id = ui->combo_availscreens->currentText(); 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; } + if(SCREENS[i].ID==id){ + ui->combo_resolutions->clear(); + for(int r=0; r<SCREENS[i].resList.length(); r++){ + ui->combo_resolutions->addItem(SCREENS[i].resList[r].section(" ",0,0, QString::SectionSkipEmpty)); + if(SCREENS[i].resList[r].contains("+")){ ui->combo_resolutions->setCurrentIndex(r); } //preferred resolution + } + break; + } } - //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; } +void MainUI::tileScreensY(bool activeonly){ + //qDebug() << "Tile Windows in Y Dimension"; + QList<QMdiSubWindow*> wins = ui->mdiArea->subWindowList(); + QMdiSubWindow *active = ui->mdiArea->currentSubWindow(); + QRegion total; + int ypos = 0; + QMdiSubWindow *cur = 0; + while(!wins.isEmpty()){ + cur=0; + for(int i=0; i<wins.length(); i++){ + if(wins[i]==active && wins.length()>1){ continue; } //ensure active window is last + if(cur==0){ cur = wins[i]; } //first one + else if(wins[i]->pos().y() < cur->pos().y()){ cur = wins[i]; } + } + if(cur==0){ + //Note: This should **never** happen + qDebug() << "No windows found below y=:" << ypos; + //need to move the reference point + QRect bounding = total.boundingRect(); + ypos+= (bounding.height()/2); + }else{ + if(total.isNull()){ + //First window handled + if(!activeonly || cur==active){ cur->move(cur->pos().x(), ypos); } + }else{ + int newy = ypos; + bool overlap = true; + while(overlap){ + QRegion tmp(cur->pos().x(), newy, cur->width(), cur->height()); + QRegion diff = tmp.subtracted(total); + overlap = (diff.boundingRect()!=tmp.boundingRect()); + //qDebug() << "Check Y Overlap:" << newy << overlap << tmp.boundingRect() << diff.boundingRect(); + if(overlap){ + QRect bound = diff.boundingRect(); + if(bound.isNull()){ newy+=cur->height(); } + else if(newy!=bound.top()){ newy = bound.top(); } + else if(newy!=bound.bottom()){ newy = bound.bottom() + 1; } + else{ newy++; } //make sure it always changes - no infinite loops!! + } + } + if(!activeonly || cur==active){ cur->move(cur->pos().x(), newy); } + } + total = total.united(cur->geometry()); + wins.removeAll(cur); + } } - //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(); +void MainUI::tileScreensX(bool activeonly){ + //qDebug() << "Tile Windows in X Dimension"; + QList<QMdiSubWindow*> wins = ui->mdiArea->subWindowList(); + QMdiSubWindow *active = ui->mdiArea->currentSubWindow(); + QRegion total; + int xpos = 0; + QMdiSubWindow *cur = 0; + while(!wins.isEmpty()){ + cur=0; + for(int i=0; i<wins.length(); i++){ + if(wins[i]==active && wins.length()>1){ continue; } //ensure active window is last + if(cur==0){ cur = wins[i]; } //first one + else if(wins[i]->pos().x() < cur->pos().x()){ cur = wins[i]; } + } + if(cur==0){ + //Note: This should **never** happen + qDebug() << "No windows found left of x=:" << xpos; + //need to move the reference point + QRect bounding = total.boundingRect(); + xpos+= (bounding.width()/2); + }else{ + if(total.isNull()){ + //First window handled + if(!activeonly || cur==active){ cur->move(xpos, cur->pos().y()); } + }else{ + int newx = xpos; + bool overlap = true; + while(overlap){ + QRegion tmp(newx, cur->pos().y(), cur->width(), cur->height()); + QRegion diff = tmp.subtracted(total); + overlap = (diff.boundingRect()!=tmp.boundingRect()); + //qDebug() << "Check X Overlap:" << newx << overlap << tmp.boundingRect() << diff.boundingRect(); + if(overlap){ + QRect bound = diff.boundingRect(); + if(bound.isNull()){ newx+=cur->width(); } + else if(newx!=bound.left()){ newx = bound.left(); } + else if(newx!=bound.right()){ newx = bound.right() + 1; } + else{ newx++; }//make sure it always changes - no infinite loops!! + }else{ + qDebug() << "Found Area:" << tmp << diff << newx; + } + } + if(!activeonly || cur==active){ cur->move(newx, cur->pos().y()); } + } + total = total.united(cur->geometry()); + wins.removeAll(cur); + } } - 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; } +} + +void MainUI::tileScreens(){ + tileScreensY(); + tileScreensX(); +} + +void MainUI::tileSingleScreen(QAction* act){ + if(act->whatsThis()=="X"){ + tileScreensX(true); + }else if(act->whatsThis()=="Y"){ + tileScreensY(true); + }else if(act->whatsThis()=="XY"){ + tileScreensX(true); + tileScreensY(true); + }else if(act->whatsThis()=="YX"){ + tileScreensY(true); + tileScreensX(true); } - //Now run the command - QStringList opts = currentOpts(); - opts << "--output" << device << "--off"; - LUtils::runCmd("xrandr", opts); - QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); +} + +void MainUI::DeactivateScreen(){ + QMdiSubWindow *cur = ui->mdiArea->currentSubWindow(); + if(cur==0){ return; } + cur->widget()->setEnabled( !cur->widget()->isEnabled() ); //toggle it between enabled/disabled } 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(); + QStringList res = ui->combo_resolutions->currentText().split("x"); + //Find the screen infor associated with this ID 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(SCREENS[i].ID==ID){ + SCREENS[i].isactive = true; + SCREENS[i].geom.setSize( QSize(res[0].toInt(), res[1].toInt()) ); + SCREENS[i].applyChange = 2; //need to activate this monitor + AddScreenToWidget(SCREENS[i]); + break; } - if(setprimary){ SCREENS[i].isprimary = SCREENS[i].ID==it->whatsThis(); } } + tileScreensX(true); + //Now remove that option from the "new" list + ui->combo_availscreens->removeItem(ui->combo_availscreens->currentIndex()); + 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); + } +} + +void MainUI::ApplyChanges(){ + SyncBackend(); //Now run the command - QStringList opts = currentOpts(); - LUtils::runCmd("xrandr", opts); + RRSettings::Apply(SCREENS); + //And update the UI and WM in a moment QTimer::singleShot(500, this, SLOT(UpdateScreens()) ); + QTimer::singleShot(1000, this, SLOT(RestartFluxbox()) ); +} + +void MainUI::SaveSettings(){ + SyncBackend(); + RRSettings::SaveScreens(SCREENS); +} + +void MainUI::RestartFluxbox(){ + QProcess::startDetached("killall fluxbox"); } diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.h b/src-qt5/core-utils/lumina-xconfig/MainUI.h index 5a1a62cc..d1abc153 100644 --- a/src-qt5/core-utils/lumina-xconfig/MainUI.h +++ b/src-qt5/core-utils/lumina-xconfig/MainUI.h @@ -11,6 +11,10 @@ #include <QRect> #include <QString> #include <QList> +#include <QMdiArea> +#include <QMdiSubWindow> +#include <QMenu> +#include <QAction> #include "ScreenSettings.h" @@ -34,20 +38,32 @@ public slots: private: Ui::MainUI *ui; QList<ScreenInfo> SCREENS; + double scaleFactor; + QMenu *singleTileMenu; + ScreenInfo currentScreenInfo(); - QStringList currentOpts(); + //QStringList currentOpts(); + QString currentSelection(); void AddScreenToWidget(ScreenInfo); + void SyncBackend(); //sync backend structures to current settings private slots: void UpdateScreens(); void ScreenSelected(); - void MoveScreenLeft(); - void MoveScreenRight(); - void DeactivateScreen(QString device = ""); + void updateNewScreenResolutions(); + void tileScreensY(bool activeonly = false); + void tileScreensX(bool activeonly = false); + void tileScreens(); + void tileSingleScreen(QAction*); + void showMenu(){ singleTileMenu->popup(QCursor::pos()); } + + void DeactivateScreen(); void ActivateScreen(); void ApplyChanges(); //config changes + void SaveSettings(); + void RestartFluxbox(); }; #endif diff --git a/src-qt5/core-utils/lumina-xconfig/MainUI.ui b/src-qt5/core-utils/lumina-xconfig/MainUI.ui index de1cc18d..872df95b 100644 --- a/src-qt5/core-utils/lumina-xconfig/MainUI.ui +++ b/src-qt5/core-utils/lumina-xconfig/MainUI.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>408</width> - <height>321</height> + <width>560</width> + <height>548</height> </rect> </property> <property name="windowTitle"> @@ -18,52 +18,41 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> - <widget class="QListWidget" name="list_screens"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> + <widget class="QMdiArea" name="mdiArea"> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>100</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>100</height> - </size> - </property> - <property name="flow"> - <enum>QListView::LeftToRight</enum> - </property> - <property name="viewMode"> - <enum>QListView::ListMode</enum> - </property> - <property name="uniformItemSizes"> - <bool>true</bool> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - <property name="selectionRectVisible"> - <bool>true</bool> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> </property> </widget> </item> <item> - <layout class="QVBoxLayout" name="verticalLayout_3"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QToolButton" name="tool_deactivate"> + <property name="toolTip"> + <string>Disable Current Screen</string> + </property> <property name="text"> - <string>...</string> + <string notr="true">...</string> </property> </widget> </item> <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -71,22 +60,42 @@ <property name="sizeHint" stdset="0"> <size> <width>20</width> - <height>0</height> + <height>40</height> </size> </property> </spacer> </item> <item> - <widget class="QToolButton" name="tool_moveleft"> + <widget class="QToolButton" name="tool_tileX"> <property name="text"> - <string>...</string> + <string notr="true">...</string> + </property> + <property name="icon"> + <iconset theme="format-view-column"/> </property> </widget> </item> <item> - <widget class="QToolButton" name="tool_moveright"> + <widget class="QToolButton" name="tool_tileY"> <property name="text"> - <string>...</string> + <string notr="true">...</string> + </property> + <property name="icon"> + <iconset theme="format-view-agenda"/> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_tile"> + <property name="toolTip"> + <string>Tile Screens</string> + </property> + <property name="text"> + <string notr="true">...</string> + </property> + <property name="icon"> + <iconset theme="format-view-grid-small"> + <normaloff>.</normaloff>.</iconset> </property> </widget> </item> @@ -97,7 +106,7 @@ <item> <widget class="QTabWidget" name="tabWidget"> <property name="currentIndex"> - <number>0</number> + <number>1</number> </property> <widget class="QWidget" name="tab_config"> <attribute name="title"> @@ -142,47 +151,23 @@ </item> </layout> </item> - <item row="2" column="1"> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> + <property name="text"> + <string>Rotation:</string> </property> - </spacer> - </item> - <item row="3" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QToolButton" name="tool_applyconfig"> - <property name="text"> - <string>Apply Settings</string> - </property> - <property name="toolButtonStyle"> - <enum>Qt::ToolButtonTextBesideIcon</enum> - </property> - </widget> - </item> - </layout> + </widget> </item> <item row="1" column="1"> + <widget class="QComboBox" name="combo_rotation"/> + </item> + <item row="2" column="1"> <widget class="QCheckBox" name="check_primary"> <property name="text"> <string>Primary Screen</string> @@ -208,6 +193,13 @@ <string>Available Screens</string> </property> <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="2"> + <widget class="QPushButton" name="push_activate"> + <property name="text"> + <string>Enable Screen</string> + </property> + </widget> + </item> <item row="0" column="0"> <widget class="QComboBox" name="combo_availscreens"> <property name="toolTip"> @@ -216,26 +208,12 @@ </widget> </item> <item row="0" column="1"> - <widget class="QComboBox" name="combo_location"> + <widget class="QComboBox" name="combo_resolutions"> <property name="toolTip"> <string>Location to insert the screen</string> </property> </widget> </item> - <item row="0" column="2"> - <widget class="QComboBox" name="combo_cscreens"> - <property name="toolTip"> - <string>Current screens</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QPushButton" name="push_activate"> - <property name="text"> - <string>Enable Screen</string> - </property> - </widget> - </item> </layout> </widget> </item> @@ -279,6 +257,33 @@ </spacer> </item> <item> + <widget class="QToolButton" name="tool_applyconfig"> + <property name="text"> + <string>Apply</string> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="tool_save"> + <property name="toolTip"> + <string>Save current settings as user defaults</string> + </property> + <property name="text"> + <string>Save</string> + </property> + <property name="icon"> + <iconset theme="document-save"> + <normaloff>.</normaloff>.</iconset> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + <item> <widget class="QPushButton" name="push_close"> <property name="text"> <string>Close</string> diff --git a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp index 91e1f498..99cfc918 100644 --- a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp +++ b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.cpp @@ -21,33 +21,26 @@ void RRSettings::ApplyPrevious(){ QString primary; QStringList avail; for(int i=0; i<screens.length(); i++){ - //if(screens[i].order>=0){screens[i].order = -1; } //reset all screen orders (need to re-check all) if(devs.contains(screens[i].ID) && screens[i].isavailable){ //only load settings for monitors which are currently attached set.beginGroup(screens[i].ID); screens[i].geom = set.value("geometry", QRect()).toRect(); screens[i].isprimary = set.value("isprimary", false).toBool(); if(screens[i].isprimary){ primary = screens[i].ID; } - screens[i].isactive = lastactive.contains(screens[i].ID); - screens[i].order = (screens[i].isactive ? -1 : -3); //check/ignore + screens[i].applyChange = (screens[i].isactive && !lastactive.contains(screens[i].ID) ? 1 : 0); //disable/ignore + screens[i].rotation = set.value("rotation",0).toInt(); set.endGroup(); - }else if(screens[i].isavailable){ - screens[i].order = -2; //needs activation/placement - }else{ - screens[i].order = -3; //ignored + }else if(screens[i].isactive){ + screens[i].applyChange = 1; //disable monitor - not enabled in the default settings } - //Now clean up the list as needed - if(screens[i].order < -2){ screens.removeAt(i); i--; } //just remove it (less to loop through later) - else{ avail << screens[i].ID; } //needed for some checks later - make it simple } - //NOTE ABOUT orders: -1: check geom, -2: auto-add to end, -3: ignored - + //Quick checks for simple systems - just use current X config as-is - if(devs.isEmpty() && (avail.filter("LVDS").isEmpty() || screens.length()==1) ){ return; } + if(devs.isEmpty() && (avail.filter("LVDS").isEmpty() || screens.length()==1) ){ return; } //Typical ID's: LVDS-[], DVI-I-[], DP-[], HDMI-[], VGA-[] - //"LVDS" is the built-in laptop display normally + //"LVDS" or "eDP" is the built-in laptop display normally if(primary.isEmpty()){ - QStringList priority; priority << "LVDS" << "DP" << "HDMI" << "DVI" << "VGA"; + QStringList priority; priority << "LVDS" << "eDP" << "DP" << "HDMI" << "DVI" << "VGA"; for(int i=0; i<priority.length() && primary.isEmpty(); i++){ QStringList filter = avail.filter(priority[i]); if(!filter.isEmpty()){ filter.sort(); primary = filter.first(); } @@ -55,44 +48,8 @@ void RRSettings::ApplyPrevious(){ if(primary.isEmpty()){ primary = avail.first(); } } //Ensure only one monitor is primary, and reset a few flags - for(int i=0; i<screens.length(); i++){ - if(screens[i].ID!=primary){ screens[i].isprimary = false; } - screens[i].isactive = true; //we want all these monitors to be active eventually - } - // Handle all the available monitors - int handled = 0; - int cx = 0; //current x point - while(handled<screens.length()){ - //Go through horizontally and place monitors (TO-DO: Vertical placement not handled yet) - int next = -1; - int diff = -1; - for(int i=0; i<screens.length(); i++){ - if(screens[i].order==-1){ - if(diff<0 || ((screens[i].geom.x()-cx) < diff)){ - diff = screens[i].geom.x()-cx; - next = i; - } - } - }//end loop over screens - if(next<0){ - //Go through and start adding the non-assigned screens to the end - for(int i=0; i<screens.length(); i++){ - if(screens[i].order==-2){ - if(diff<0 || ((screens[i].geom.x()-cx) < diff)){ - diff = screens[i].geom.x()-cx; - next = i; - } - } - } //end loop over screens - } - if(next>=0){ - cx+=screens[next].geom.width(); - screens[next].order = handled; handled++; - }else{ - //Still missing monitors (vertical alignment?) - qDebug() << "Unhandled Monitors:" << screens.length()-handled; - break; - } + for(int i=0; i<screens.length(); i++){ + if(screens[i].ID!=primary){ screens[i].isprimary = false; } } //Now reset the display with xrandr RRSettings::Apply(screens); @@ -106,17 +63,19 @@ QList<ScreenInfo> RRSettings::CurrentScreens(){ for(int i=0; i<info.length(); i++){ if(info[i].contains("connected") ){ //qDebug() << "xrandr info:" << info[i]; - if(!cscreen.ID.isEmpty()){ + if(!cscreen.ID.isEmpty()){ SCREENS << cscreen; //current screen finished - save it into the array - cscreen = ScreenInfo(); //Now create a new structure - } + 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; + //Pull the monitor rotation mode out as well (last word before the parenthesis) + QString devrotate = info[i].section("(",0,0).split(" ",QString::SkipEmptyParts).last(); + //qDebug() << " - ID:" <<dev << "Current Geometry:" << devres; //qDebug() << " - Res:" << devres; if( !devres.contains("x") || !devres.contains("+") ){ devres.clear(); } //qDebug() << " - Res (modified):" << devres; @@ -127,17 +86,21 @@ QList<ScreenInfo> RRSettings::CurrentScreens(){ }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; + //qDebug() << "Create new Screen entry:" << dev << devres << devrotate << info[i].section("(",0,0); 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() ); cscreen.isavailable = true; cscreen.isactive = true; + if(devrotate=="left"){ cscreen.rotation = -90; } + else if(devrotate=="right"){ cscreen.rotation = 90; } + else if(devrotate=="inverted"){ cscreen.rotation = 180; } + else{ cscreen.rotation = 0; } }else if(info[i].contains(" connected")){ //Device that is connected, but not attached - qDebug() << "Create new Screen entry:" << dev << "none"; + //qDebug() << "Create new Screen entry:" << dev << "none"; cscreen.ID = dev; - cscreen.order = -2; //flag this right now as a non-active screen + //cscreen.order = -2; //flag this right now as a non-active screen cscreen.isavailable = true; cscreen.isactive = false; } @@ -164,6 +127,7 @@ bool RRSettings::SaveScreens(QList<ScreenInfo> screens){ set.beginGroup(screens[i].ID); set.setValue("geometry", screens[i].geom); set.setValue("isprimary", screens[i].isprimary); + set.setValue("rotation", screens[i].rotation); set.endGroup(); } set.setValue("lastActive",active); @@ -173,17 +137,24 @@ bool RRSettings::SaveScreens(QList<ScreenInfo> screens){ } return true; } - + //Apply screen configuration void RRSettings::Apply(QList<ScreenInfo> screens){ //Read all the settings and create the xrandr options to maintain these settings QStringList opts; - qDebug() << "Apply:" << screens.length(); + //qDebug() << "Apply:" << screens.length(); for(int i=0; i<screens.length(); i++){ - qDebug() << " -- Screen:" << i << screens[i].ID << screens[i].isactive << screens[i].order; - if(screens[i].order <0 || !screens[i].isactive){ 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()); + qDebug() << " -- Screen:" << i << screens[i].ID << screens[i].isactive; + if( !screens[i].isactive){ continue; } //skip this screen - non-active + else if(screens[i].applyChange==1){ opts << "--output" << screens[i].ID << "--off"; continue; } //deactivate a screen + opts << "--output" << screens[i].ID; + if(screens[i].applyChange==2){ opts << "--auto"; } + else{ opts << "--mode" << QString::number(screens[i].geom.width())+"x"+QString::number(screens[i].geom.height()); } opts << "--pos" << QString::number(screens[i].geom.x())+"x"+QString::number(screens[i].geom.y()); + if(screens[i].rotation==-90){ opts << "--rotate" << "left"; } + else if(screens[i].rotation==90){ opts << "--rotate" << "right"; } + else if(screens[i].rotation==180){ opts << "--rotate" << "inverted"; } + else{ opts << "--rotate" << "normal"; } if(screens[i].isprimary){ opts << "--primary"; } } qDebug() << "Run command: xrandr" << opts; diff --git a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h index 5826f804..b1b9cad9 100644 --- a/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h +++ b/src-qt5/core-utils/lumina-xconfig/ScreenSettings.h @@ -13,21 +13,24 @@ #include <QStringList> class ScreenInfo{ - public: + public: QString ID; QRect geom; //screen geometry bool isprimary; bool isactive; bool isavailable; - int order; //left to right + int applyChange; //[<=0: do nothing, 1: deactivate, 2: activate] QStringList resList; + int rotation; //possible values: [-90, 0, 90, 180] + //Initial Defaults ScreenInfo(){ - order = -1; //initial value is invalid + applyChange = -1; //initial value is invalid isprimary = false; isactive = false; isavailable = false; + rotation = 0; //no rotation by default } ~ScreenInfo(){} }; @@ -42,9 +45,9 @@ public: //Save the screen config for later static bool SaveScreens(QList<ScreenInfo> screens); - + //Apply screen configuration static void Apply(QList<ScreenInfo> screens); -}; +}; #endif diff --git a/src-qt5/core-utils/lumina-xconfig/i18n/lumina-xconfig_en_AU.ts b/src-qt5/core-utils/lumina-xconfig/i18n/lumina-xconfig_en_AU.ts new file mode 100644 index 00000000..6401616d --- /dev/null +++ b/src-qt5/core-utils/lumina-xconfig/i18n/lumina-xconfig_en_AU.ts @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE TS> +<TS version="2.1"> +</TS> diff --git a/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro b/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro index 2fb792d6..2cfb64ec 100644 --- a/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro +++ b/src-qt5/core-utils/lumina-xconfig/lumina-xconfig.pro @@ -38,6 +38,7 @@ TRANSLATIONS = i18n/lumina-xconfig_af.ts \ i18n/lumina-xconfig_el.ts \ i18n/lumina-xconfig_en_GB.ts \ i18n/lumina-xconfig_en_ZA.ts \ + i18n/lumina-xconfig_en_AU.ts \ i18n/lumina-xconfig_es.ts \ i18n/lumina-xconfig_et.ts \ i18n/lumina-xconfig_eu.ts \ |