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")
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)
find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS X11Extras)
endif()

@ -26,8 +26,10 @@
#include "screenpool.h"
#include <QAction>
#include <QApplication>
#include <QScreen>
#include <QDebug>
#include <QDesktopWidget>
#include <QQmlContext>
#include <Plasma>
@ -96,9 +98,11 @@ void DockCorona::load()
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::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();
}
@ -240,15 +244,110 @@ QRect DockCorona::availableScreenRect(int id) const
void DockCorona::addOutput(QScreen *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()
{
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)
{
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
@ -349,7 +448,7 @@ int DockCorona::screenForContainment(const Plasma::Containment *containment) con
//It is also correct for desktops *that have the correct activity()*
//a containment with lastScreen() == 0 but another activity,
//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()) {
// 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()};
if (containment->screen() >= 0) {
QString connector = m_screenPool->connector(containment->screen());
int id = containment->screen();
if (id == -1) {
id = containment->lastScreen();
}
if (id >= 0) {
QString connector = m_screenPool->connector(id);
bool found{false};
foreach(auto scr, qGuiApp->screens()){
if (scr && scr->name() == connector){
@ -417,6 +522,7 @@ void DockCorona::addDock(Plasma::Containment *containment)
void DockCorona::destroyedChanged(bool destroyed)
{
qDebug() << "dock containment destroyed changed!!!!";
Plasma::Containment *sender = qobject_cast<Plasma::Containment *>(QObject::sender());
if (!sender) {
@ -434,6 +540,7 @@ void DockCorona::destroyedChanged(bool destroyed)
void DockCorona::dockContainmentDestroyed(QObject *cont)
{
qDebug() << "dock containment destroyed!!!!";
auto view = m_waitingDockViews.take(static_cast<Plasma::Containment *>(cont));
if (view)

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

@ -65,8 +65,10 @@ DockView::DockView(Plasma::Corona *corona, QScreen *targetScreen)
connect(this, &DockView::containmentChanged
, this, [&]() {
qDebug() << "entered creating step 1...";
if (!this->containment())
return;
qDebug() << "entered creating step 2...";
if (!m_visibility) {
m_visibility = new VisibilityManager(this);
@ -114,7 +116,8 @@ void DockView::init()
{
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, &QQuickWindow::widthChanged, this, &DockView::widthChanged);
connect(this, &QQuickWindow::heightChanged, this, &DockView::heightChanged);
@ -140,7 +143,7 @@ void DockView::init()
void DockView::adaptToScreen(QScreen *screen)
{
/* if (!screen) {
/* if (!screen) {
return;
}
@ -183,6 +186,7 @@ void DockView::setScreenToFollow(QScreen *screen)
}
m_screenToFollow = screen;
m_screenToFollowId = screen->name();
qDebug() << "adapting to screen...";
@ -194,18 +198,51 @@ void DockView::setScreenToFollow(QScreen *screen)
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)
{
if (!scr || m_screenToFollow == scr) {
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
//layouts it needs inverstigation!!!
// setScreen(m_screenToFollow);
// syncGeometry();
setScreen(m_screenToFollow);
syncGeometry();
}*/
// emit docksCountChanged();
}
void DockView::addNewDock()
@ -247,10 +284,7 @@ QScreen *DockView::atScreens(QQmlListProperty<QScreen> *property, int index)
QString DockView::currentScreen() const
{
if (m_screenToFollow)
return m_screenToFollow->name();
return "";
return m_screenToFollowId;
}
void DockView::showConfigurationInterface(Plasma::Applet *applet)
@ -428,13 +462,30 @@ inline void DockView::syncGeometry()
//if (qGuiApp->primaryScreen() && screen() != qGuiApp->primaryScreen()){
// setScreen(qGuiApp->primaryScreen());
//}
if (screen() != m_screenToFollow) {
setScreenToFollow(m_screenToFollow);
bool found{false};
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();
resizeWindow();
updatePosition();
}
// qDebug() << "dock geometry:" << qRectToStr(geometry());
}

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

@ -18,16 +18,26 @@
*/
#include "screenpool.h"
#include <config-latte.h>
#include <QGuiApplication>
#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)
: QObject(parent),
m_configGroup(KConfigGroup(config, QStringLiteral("ScreenConnectors")))
{
qApp->installNativeEventFilter(this);
m_configSaveTimer.setSingleShot(true);
connect(&m_configSaveTimer, &QTimer::timeout, this, [this]() {
connect(&m_configSaveTimer, &QTimer::timeout, this, [this](){
m_configGroup.sync();
});
}
@ -39,10 +49,8 @@ void ScreenPool::load()
m_idForConnector.clear();
QScreen *primary = qGuiApp->primaryScreen();
if (primary) {
m_primaryConnector = primary->name();
if (!m_primaryConnector.isEmpty()) {
m_connectorForId[0] = m_primaryConnector;
m_idForConnector[m_primaryConnector] = 0;
@ -52,7 +60,6 @@ void ScreenPool::load()
//restore the known ids to connector mappings
foreach (const QString &key, m_configGroup.keyList()) {
QString connector = m_configGroup.readEntry(key, QString());
if (!key.isEmpty() && !connector.isEmpty() &&
!m_connectorForId.contains(key.toInt()) &&
!m_idForConnector.contains(connector)) {
@ -68,7 +75,7 @@ void ScreenPool::load()
// containment->screen() will return an incorrect -1
// at startup, if it' asked before corona::addOutput()
// 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())) {
insertScreenMapping(firstAvailableId(), screen->name());
}
@ -90,7 +97,6 @@ void ScreenPool::setPrimaryConnector(const QString &primary)
if (m_primaryConnector == primary) {
return;
}
Q_ASSERT(m_idForConnector.contains(primary));
int oldIdForPrimary = m_idForConnector.value(primary);
@ -106,11 +112,9 @@ void ScreenPool::setPrimaryConnector(const QString &primary)
void ScreenPool::save()
{
QMap<int, QString>::const_iterator i;
for (i = m_connectorForId.constBegin(); i != m_connectorForId.constEnd(); ++i) {
m_configGroup.writeEntry(QString::number(i.key()), i.value());
}
//write to disck every 30 seconds at most
m_configSaveTimer.start(30000);
}
@ -148,14 +152,12 @@ QString ScreenPool::connector(int id) const
int ScreenPool::firstAvailableId() const
{
int i = 0;
//find the first integer not stored in m_connectorForId
//m_connectorForId is the only map, so the ids are sorted
foreach (int existingId, m_connectorForId.keys()) {
if (i != existingId) {
return i;
}
++i;
}
@ -167,4 +169,39 @@ QList <int> ScreenPool::knownIds() const
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"

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

Loading…
Cancel
Save