improvements to add/remove docks on screen demand

pull/1/head
Michail Vourlakos 8 years ago
parent 8a7bb2942c
commit 9259a28cde

@ -28,7 +28,7 @@ set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries"
PURPOSE "Required for building the X11 based workspace") PURPOSE "Required for building the X11 based workspace")
if(X11_FOUND) if(X11_FOUND)
find_package(XCB MODULE REQUIRED COMPONENTS XCB) find_package(XCB MODULE REQUIRED COMPONENTS XCB RANDR)
set_package_properties(XCB PROPERTIES TYPE REQUIRED) set_package_properties(XCB PROPERTIES TYPE REQUIRED)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS X11Extras) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS X11Extras)
endif() endif()

@ -26,8 +26,10 @@
#include "screenpool.h" #include "screenpool.h"
#include <QAction> #include <QAction>
#include <QApplication>
#include <QScreen> #include <QScreen>
#include <QDebug> #include <QDebug>
#include <QDesktopWidget>
#include <QQmlContext> #include <QQmlContext>
#include <Plasma> #include <Plasma>
@ -96,9 +98,11 @@ void DockCorona::load()
m_activitiesStarting = false; m_activitiesStarting = false;
connect(qGuiApp, &QGuiApplication::screenAdded, this, &DockCorona::addOutput, Qt::UniqueConnection); // connect(qGuiApp, &QGuiApplication::screenAdded, this, &DockCorona::addOutput, Qt::UniqueConnection);
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DockCorona::primaryOutputChanged, Qt::UniqueConnection); connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DockCorona::primaryOutputChanged, Qt::UniqueConnection);
connect(qGuiApp, &QGuiApplication::screenRemoved, this, &DockCorona::screenRemoved, Qt::UniqueConnection); // connect(qGuiApp, &QGuiApplication::screenRemoved, this, &DockCorona::screenRemoved, Qt::UniqueConnection);
connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, &DockCorona::screenCountChanged);
connect(m_screenPool, &ScreenPool::primaryPoolChanged, this, &DockCorona::screenCountChanged);
loadLayout(); loadLayout();
} }
@ -240,15 +244,110 @@ QRect DockCorona::availableScreenRect(int id) const
void DockCorona::addOutput(QScreen *screen) void DockCorona::addOutput(QScreen *screen)
{ {
Q_ASSERT(screen); Q_ASSERT(screen);
/* qDebug() << "screen added +++ "<<screen->name();
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
}*/
/* foreach(auto cont, containments()) {
if (m_screenPool->connector(cont->screen()) == screen->name()) {
auto view = m_dockViews.take(cont);
if (!view) {
addDock(cont);
}
}
} */
} }
void DockCorona::primaryOutputChanged() void DockCorona::primaryOutputChanged()
{ {
qDebug() << "primary changed ### "<< qGuiApp->primaryScreen()->name();
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
}
if (m_dockViews.count()==1 && qGuiApp->screens().size()==1) {
foreach(auto view, m_dockViews) {
view->setScreenToFollow(qGuiApp->primaryScreen());
}
}
} }
void DockCorona::screenRemoved(QScreen *screen) void DockCorona::screenRemoved(QScreen *screen)
{ {
Q_ASSERT(screen); Q_ASSERT(screen);
/* qDebug() << "screen removed --- "<<screen->name();
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
}*/
/* if (m_dockViews.size() > 1) {
foreach(auto cont, containments()) {
if (m_screenPool->connector(cont->screen()) == screen->name()) {
auto view = m_dockViews.take(cont);
if (view) {
view->deleteLater();
}
}
}
} */
}
void DockCorona::screenCountChanged()
{
QTimer::singleShot(2500, this, &DockCorona::screenCountChangedTimer);
}
void DockCorona::screenCountChangedTimer()
{
qDebug() << "screen count changed -+-+ "<< qGuiApp->screens().size();
qDebug() << "adding consideration....";
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
foreach(auto cont, containments()) {
int id = cont->screen();
if (id == -1){
id = cont->lastScreen();
}
if ((m_screenPool->connector(id) == scr->name()) && (!m_dockViews.contains(cont))) {
qDebug() << "screen Count signal: view must be added... for:"<< scr->name();
addDock(cont);
}
}
}
qDebug() << "removing consideration....";
foreach(auto view, m_dockViews){
bool found{false};
foreach(auto scr, qGuiApp->screens()){
int id = view->containment()->screen();
if (id == -1){
id = view->containment()->lastScreen();
}
if(scr->name() == view->currentScreen()){
found = true;
break;
}
}
if (!found && (m_dockViews.size()>1) && m_dockViews.contains(view->containment())) {
qDebug() << "screen Count signal: view must be deleted... for:"<<view->currentScreen();
auto viewToDelete = m_dockViews.take(view->containment());
viewToDelete->deleteLater();
} else {
view->reconsiderScreen();
}
}
qDebug() << "end of screens count change....";
} }
int DockCorona::primaryScreenId() const int DockCorona::primaryScreenId() const
@ -349,7 +448,7 @@ int DockCorona::screenForContainment(const Plasma::Containment *containment) con
//It is also correct for desktops *that have the correct activity()* //It is also correct for desktops *that have the correct activity()*
//a containment with lastScreen() == 0 but another activity, //a containment with lastScreen() == 0 but another activity,
//won't be associated to a screen //won't be associated to a screen
// qDebug() << "ShellCorona screenForContainment: " << containment << " Last screen is " << containment->lastScreen(); // qDebug() << "ShellCorona screenForContainment: " << containment << " Last screen is " << containment->lastScreen();
for (auto screen : qGuiApp->screens()) { for (auto screen : qGuiApp->screens()) {
// containment->lastScreen() == m_screenPool->id(screen->name()) to check if the lastScreen refers to a screen that exists/it's known // containment->lastScreen() == m_screenPool->id(screen->name()) to check if the lastScreen refers to a screen that exists/it's known
@ -384,8 +483,14 @@ void DockCorona::addDock(Plasma::Containment *containment)
QScreen *nextScreen{qGuiApp->primaryScreen()}; QScreen *nextScreen{qGuiApp->primaryScreen()};
if (containment->screen() >= 0) { int id = containment->screen();
QString connector = m_screenPool->connector(containment->screen());
if (id == -1) {
id = containment->lastScreen();
}
if (id >= 0) {
QString connector = m_screenPool->connector(id);
bool found{false}; bool found{false};
foreach(auto scr, qGuiApp->screens()){ foreach(auto scr, qGuiApp->screens()){
if (scr && scr->name() == connector){ if (scr && scr->name() == connector){
@ -417,6 +522,7 @@ void DockCorona::addDock(Plasma::Containment *containment)
void DockCorona::destroyedChanged(bool destroyed) void DockCorona::destroyedChanged(bool destroyed)
{ {
qDebug() << "dock containment destroyed changed!!!!";
Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender()); Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender());
if (!sender) { if (!sender) {
@ -434,6 +540,7 @@ void DockCorona::destroyedChanged(bool destroyed)
void DockCorona::dockContainmentDestroyed(QObject *cont) void DockCorona::dockContainmentDestroyed(QObject *cont)
{ {
qDebug() << "dock containment destroyed!!!!";
auto view = m_waitingDockViews.take(static_cast<Plasma::Containment *>(cont)); auto view = m_waitingDockViews.take(static_cast<Plasma::Containment *>(cont));
if (view) if (view)

@ -84,6 +84,8 @@ private slots:
void addOutput(QScreen *screen); void addOutput(QScreen *screen);
void primaryOutputChanged(); void primaryOutputChanged();
void screenRemoved(QScreen *screen); void screenRemoved(QScreen *screen);
void screenCountChanged();
void screenCountChangedTimer();
private: private:
bool appletExists(uint containmentId, uint appletId) const; bool appletExists(uint containmentId, uint appletId) const;

@ -65,8 +65,10 @@ DockView::DockView(Plasma::Corona *corona, QScreen *targetScreen)
connect(this, &DockView::containmentChanged connect(this, &DockView::containmentChanged
, this, [&]() { , this, [&]() {
qDebug() << "entered creating step 1...";
if (!this->containment()) if (!this->containment())
return; return;
qDebug() << "entered creating step 2...";
if (!m_visibility) { if (!m_visibility) {
m_visibility = new VisibilityManager(this); m_visibility = new VisibilityManager(this);
@ -114,7 +116,8 @@ void DockView::init()
{ {
connect(this, &QQuickWindow::screenChanged, this, &DockView::screenChanged); connect(this, &QQuickWindow::screenChanged, this, &DockView::screenChanged);
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DockView::syncGeometry, Qt::UniqueConnection); connect(qGuiApp, &QGuiApplication::screenAdded, this, &DockView::reconsiderScreen);
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &DockView::reconsiderScreen);
connect(this, &DockView::screenGeometryChanged, this, &DockView::syncGeometry); connect(this, &DockView::screenGeometryChanged, this, &DockView::syncGeometry);
connect(this, &QQuickWindow::widthChanged, this, &DockView::widthChanged); connect(this, &QQuickWindow::widthChanged, this, &DockView::widthChanged);
connect(this, &QQuickWindow::heightChanged, this, &DockView::heightChanged); connect(this, &QQuickWindow::heightChanged, this, &DockView::heightChanged);
@ -140,7 +143,7 @@ void DockView::init()
void DockView::adaptToScreen(QScreen *screen) void DockView::adaptToScreen(QScreen *screen)
{ {
/* if (!screen) { /* if (!screen) {
return; return;
} }
@ -183,6 +186,7 @@ void DockView::setScreenToFollow(QScreen *screen)
} }
m_screenToFollow = screen; m_screenToFollow = screen;
m_screenToFollowId = screen->name();
qDebug() << "adapting to screen..."; qDebug() << "adapting to screen...";
@ -194,18 +198,51 @@ void DockView::setScreenToFollow(QScreen *screen)
syncGeometry(); syncGeometry();
} }
void DockView::reconsiderScreen()
{
qDebug() << " Delayer ";
foreach(auto scr, qGuiApp->screens()){
qDebug() << " D, found screen: "<<scr->name();
}
foreach(auto scr, qGuiApp->screens()){
if (scr && scr->name() == m_screenToFollowId){
setScreenToFollow(scr);
syncGeometry();
}
}
emit docksCountChanged();
}
void DockView::screenChanged(QScreen *scr) void DockView::screenChanged(QScreen *scr)
{ {
if (!scr || m_screenToFollow == scr) { if (!scr || m_screenToFollow == scr) {
return; return;
} }
emit docksCountChanged(); qDebug() << "Screen inconsistency!!! :" << scr->name() << " - " <<m_screenToFollow->name();
QTimer::singleShot(2500, this, &DockView::reconsiderScreen);
/*bool found{false};
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
if (scr && scr == m_screenToFollow){
found=true;
//break;
}
}
if (found) {
//IMPORTAT!!! this code creates crashes when changing plasma //IMPORTAT!!! this code creates crashes when changing plasma
//layouts it needs inverstigation!!! //layouts it needs inverstigation!!!
// setScreen(m_screenToFollow); setScreen(m_screenToFollow);
// syncGeometry(); syncGeometry();
}*/
// emit docksCountChanged();
} }
void DockView::addNewDock() void DockView::addNewDock()
@ -247,10 +284,7 @@ QScreen *DockView::atScreens(QQmlListProperty<QScreen> *property, int index)
QString DockView::currentScreen() const QString DockView::currentScreen() const
{ {
if (m_screenToFollow) return m_screenToFollowId;
return m_screenToFollow->name();
return "";
} }
void DockView::showConfigurationInterface(Plasma::Applet *applet) void DockView::showConfigurationInterface(Plasma::Applet *applet)
@ -428,13 +462,30 @@ inline void DockView::syncGeometry()
//if (qGuiApp->primaryScreen() && screen() != qGuiApp->primaryScreen()){ //if (qGuiApp->primaryScreen() && screen() != qGuiApp->primaryScreen()){
// setScreen(qGuiApp->primaryScreen()); // setScreen(qGuiApp->primaryScreen());
//} //}
if (screen() != m_screenToFollow) { bool found{false};
setScreenToFollow(m_screenToFollow); if (this->screen() != m_screenToFollow) {
qDebug() << "Sync Geometry screens incosistent!!!!";
foreach(auto scr, qGuiApp->screens()){
qDebug() << "Found screen: "<<scr->name();
if (scr && scr->name() == m_screenToFollowId){
qDebug() << " found ... ";
//setScreenToFollow(scr);
// found=true;
} }
}
QTimer::singleShot(2500, this, &DockView::reconsiderScreen);
//if (found)
// setScreenToFollow(m_screenToFollow);
} else {
found = true;
}
if (found) {
updateEnabledBorders(); updateEnabledBorders();
resizeWindow(); resizeWindow();
updatePosition(); updatePosition();
}
// qDebug() << "dock geometry:" << qRectToStr(geometry()); // qDebug() << "dock geometry:" << qRectToStr(geometry());
} }

@ -112,6 +112,7 @@ public:
QQmlListProperty<QScreen> screens(); QQmlListProperty<QScreen> screens();
static int countScreens(QQmlListProperty<QScreen> *property); static int countScreens(QQmlListProperty<QScreen> *property);
static QScreen *atScreens(QQmlListProperty<QScreen> *property, int index); static QScreen *atScreens(QQmlListProperty<QScreen> *property, int index);
void reconsiderScreen();
public slots: public slots:
Q_INVOKABLE void addNewDock(); Q_INVOKABLE void addNewDock();
@ -184,6 +185,7 @@ private:
QPointer<PlasmaQuick::ConfigView> m_configView; QPointer<PlasmaQuick::ConfigView> m_configView;
QPointer<VisibilityManager> m_visibility; QPointer<VisibilityManager> m_visibility;
QPointer<QScreen> m_screenToFollow; QPointer<QScreen> m_screenToFollow;
QString m_screenToFollowId;
//only for the mask, not to actually paint //only for the mask, not to actually paint
Plasma::FrameSvg::EnabledBorders m_enabledBorders = Plasma::FrameSvg::AllBorders; Plasma::FrameSvg::EnabledBorders m_enabledBorders = Plasma::FrameSvg::AllBorders;

@ -18,16 +18,26 @@
*/ */
#include "screenpool.h" #include "screenpool.h"
#include <config-latte.h>
#include <QGuiApplication> #include <QGuiApplication>
#include <QScreen> #include <QScreen>
#if HAVE_X11
#include <QtX11Extras/QX11Info>
#include <xcb/xcb.h>
#include <xcb/randr.h>
#include <xcb/xcb_event.h>
#endif
ScreenPool::ScreenPool(KSharedConfig::Ptr config, QObject *parent) ScreenPool::ScreenPool(KSharedConfig::Ptr config, QObject *parent)
: QObject(parent), : QObject(parent),
m_configGroup(KConfigGroup(config, QStringLiteral("ScreenConnectors"))) m_configGroup(KConfigGroup(config, QStringLiteral("ScreenConnectors")))
{ {
qApp->installNativeEventFilter(this);
m_configSaveTimer.setSingleShot(true); m_configSaveTimer.setSingleShot(true);
connect(&m_configSaveTimer, &QTimer::timeout, this, [this]() { connect(&m_configSaveTimer, &QTimer::timeout, this, [this](){
m_configGroup.sync(); m_configGroup.sync();
}); });
} }
@ -39,10 +49,8 @@ void ScreenPool::load()
m_idForConnector.clear(); m_idForConnector.clear();
QScreen *primary = qGuiApp->primaryScreen(); QScreen *primary = qGuiApp->primaryScreen();
if (primary) { if (primary) {
m_primaryConnector = primary->name(); m_primaryConnector = primary->name();
if (!m_primaryConnector.isEmpty()) { if (!m_primaryConnector.isEmpty()) {
m_connectorForId[0] = m_primaryConnector; m_connectorForId[0] = m_primaryConnector;
m_idForConnector[m_primaryConnector] = 0; m_idForConnector[m_primaryConnector] = 0;
@ -52,7 +60,6 @@ void ScreenPool::load()
//restore the known ids to connector mappings //restore the known ids to connector mappings
foreach (const QString &key, m_configGroup.keyList()) { foreach (const QString &key, m_configGroup.keyList()) {
QString connector = m_configGroup.readEntry(key, QString()); QString connector = m_configGroup.readEntry(key, QString());
if (!key.isEmpty() && !connector.isEmpty() && if (!key.isEmpty() && !connector.isEmpty() &&
!m_connectorForId.contains(key.toInt()) && !m_connectorForId.contains(key.toInt()) &&
!m_idForConnector.contains(connector)) { !m_idForConnector.contains(connector)) {
@ -68,7 +75,7 @@ void ScreenPool::load()
// containment->screen() will return an incorrect -1 // containment->screen() will return an incorrect -1
// at startup, if it' asked before corona::addOutput() // at startup, if it' asked before corona::addOutput()
// is performed, driving to the creation of a new containment // is performed, driving to the creation of a new containment
for (QScreen *screen : qGuiApp->screens()) { for (QScreen* screen : qGuiApp->screens()) {
if (!m_idForConnector.contains(screen->name())) { if (!m_idForConnector.contains(screen->name())) {
insertScreenMapping(firstAvailableId(), screen->name()); insertScreenMapping(firstAvailableId(), screen->name());
} }
@ -90,7 +97,6 @@ void ScreenPool::setPrimaryConnector(const QString &primary)
if (m_primaryConnector == primary) { if (m_primaryConnector == primary) {
return; return;
} }
Q_ASSERT(m_idForConnector.contains(primary)); Q_ASSERT(m_idForConnector.contains(primary));
int oldIdForPrimary = m_idForConnector.value(primary); int oldIdForPrimary = m_idForConnector.value(primary);
@ -106,11 +112,9 @@ void ScreenPool::setPrimaryConnector(const QString &primary)
void ScreenPool::save() void ScreenPool::save()
{ {
QMap<int, QString>::const_iterator i; QMap<int, QString>::const_iterator i;
for (i = m_connectorForId.constBegin(); i != m_connectorForId.constEnd(); ++i) { for (i = m_connectorForId.constBegin(); i != m_connectorForId.constEnd(); ++i) {
m_configGroup.writeEntry(QString::number(i.key()), i.value()); m_configGroup.writeEntry(QString::number(i.key()), i.value());
} }
//write to disck every 30 seconds at most //write to disck every 30 seconds at most
m_configSaveTimer.start(30000); m_configSaveTimer.start(30000);
} }
@ -148,14 +152,12 @@ QString ScreenPool::connector(int id) const
int ScreenPool::firstAvailableId() const int ScreenPool::firstAvailableId() const
{ {
int i = 0; int i = 0;
//find the first integer not stored in m_connectorForId //find the first integer not stored in m_connectorForId
//m_connectorForId is the only map, so the ids are sorted //m_connectorForId is the only map, so the ids are sorted
foreach (int existingId, m_connectorForId.keys()) { foreach (int existingId, m_connectorForId.keys()) {
if (i != existingId) { if (i != existingId) {
return i; return i;
} }
++i; ++i;
} }
@ -167,4 +169,39 @@ QList <int> ScreenPool::knownIds() const
return m_connectorForId.keys(); return m_connectorForId.keys();
} }
bool ScreenPool::nativeEventFilter(const QByteArray& eventType, void* message, long int* result)
{
Q_UNUSED(result);
#if HAVE_X11
// a particular edge case: when we switch the only enabled screen
// we don't have any signal about it, the primary screen changes but we have the same old QScreen* getting recycled
// see https://bugs.kde.org/show_bug.cgi?id=373880
// if this slot will be invoked many times, their//second time on will do nothing as name and primaryconnector will be the same by then
if (eventType != "xcb_generic_event_t") {
return false;
}
xcb_generic_event_t *ev = static_cast<xcb_generic_event_t *>(message);
const auto responseType = XCB_EVENT_RESPONSE_TYPE(ev);
const xcb_query_extension_reply_t* reply = xcb_get_extension_data(QX11Info::connection(), &xcb_randr_id);
if (responseType == reply->first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
if (qGuiApp->primaryScreen()->name() != primaryConnector()) {
//new screen?
if (id(qGuiApp->primaryScreen()->name()) < 0) {
insertScreenMapping(firstAvailableId(), qGuiApp->primaryScreen()->name());
}
//switch the primary screen in the pool
setPrimaryConnector(qGuiApp->primaryScreen()->name());
emit primaryPoolChanged();
}
}
#endif
return false;
}
#include "moc_screenpool.cpp" #include "moc_screenpool.cpp"

@ -24,11 +24,13 @@
#include <QHash> #include <QHash>
#include <QString> #include <QString>
#include <QTimer> #include <QTimer>
#include <QAbstractNativeEventFilter>
#include <KConfigGroup> #include <KConfigGroup>
#include <KSharedConfig> #include <KSharedConfig>
class ScreenPool : public QObject { class ScreenPool : public QObject, public QAbstractNativeEventFilter
{
Q_OBJECT Q_OBJECT
public: public:
@ -50,6 +52,12 @@ public:
//all ids that are known, included screens not enabled at the moment //all ids that are known, included screens not enabled at the moment
QList <int> knownIds() const; QList <int> knownIds() const;
signals:
void primaryPoolChanged();
protected:
bool nativeEventFilter(const QByteArray & eventType, void * message, long * result) Q_DECL_OVERRIDE;
private: private:
void save(); void save();

Loading…
Cancel
Save