summaryrefslogtreecommitdiff
path: root/kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch
diff options
context:
space:
mode:
Diffstat (limited to 'kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch')
-rw-r--r--kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch210
1 files changed, 210 insertions, 0 deletions
diff --git a/kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch b/kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch
new file mode 100644
index 00000000000..061868a573d
--- /dev/null
+++ b/kde-base/ksmserver/files/ksmserver-4.11.3-fixmultimonitor.patch
@@ -0,0 +1,210 @@
+From 3a4a7ac959c17ffd08b104bc4c5d550b5f1dfcb6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20L=C3=BCbking?= <thomas.luebking@gmail.com>
+Date: Sat, 26 Jan 2013 22:27:48 +0100
+Subject: [PATCH] improve screenlocker multiscreen behavior
+
+- pass focus to greeter under the mouse
+- share keyboard events
+- let through keyboard events for one hidden locker
+ (mouse wakeup case)
+- remove double filtering
+
+BUG: 311188
+FIXED-IN: 4.11.4
+REVIEW: 113971
+---
+ ksmserver/screenlocker/greeter/greeterapp.cpp | 92 +++++++++++++++++++++++++--
+ ksmserver/screenlocker/greeter/greeterapp.h | 1 +
+ 2 files changed, 87 insertions(+), 6 deletions(-)
+
+diff --git a/ksmserver/screenlocker/greeter/greeterapp.cpp b/ksmserver/screenlocker/greeter/greeterapp.cpp
+index 30987c1..c5e2f85 100644
+--- a/ksmserver/screenlocker/greeter/greeterapp.cpp
++++ b/ksmserver/screenlocker/greeter/greeterapp.cpp
+@@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #include <KDE/KDebug>
+ #include <KDE/KStandardDirs>
+ #include <KDE/KUser>
++#include <KDE/KWindowSystem>
+ #include <Solid/PowerManagement>
+ #include <kdeclarative.h>
+ //Plasma
+@@ -52,6 +53,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #include <X11/Xlib.h>
+ #include <fixx11h.h>
+
++// this is usable to fake a "screensaver" installation for testing
++// *must* be "0" for every public commit!
++#define TEST_SCREENSAVER 0
++
+ namespace ScreenLocker
+ {
+
+@@ -98,7 +103,11 @@ void UnlockApp::initialize()
+ KCrash::setDrKonqiEnabled(false);
+
+ KScreenSaverSettings::self()->readConfig();
++#if TEST_SCREENSAVER
++ m_showScreenSaver = true;
++#else
+ m_showScreenSaver = KScreenSaverSettings::legacySaverEnabled();
++#endif
+
+ m_structure = Plasma::PackageStructure::load("Plasma/Generic");
+ m_package = new Plasma::Package(KStandardDirs::locate("data", "ksmserver/screenlocker/"), KScreenSaverSettings::greeterQML(), m_structure);
+@@ -148,7 +157,6 @@ void UnlockApp::desktopResized()
+ this, SLOT(viewStatusChanged(QDeclarativeView::Status)));
+ view->setWindowFlags(Qt::X11BypassWindowManagerHint);
+ view->setFrameStyle(QFrame::NoFrame);
+- view->installEventFilter(this);
+
+ // engine stuff
+ KDeclarative kdeclarative;
+@@ -232,11 +240,15 @@ void UnlockApp::desktopResized()
+ ScreenSaverWindow *screensaverWindow = m_screensaverWindows.at(i);
+ screensaverWindow->setGeometry(view->geometry());
+
++#if TEST_SCREENSAVER
++ screensaverWindow->setAutoFillBackground(true);
++#else
+ QPixmap backgroundPix(screensaverWindow->size());
+ QPainter p(&backgroundPix);
+ view->render(&p);
+ p.end();
+ screensaverWindow->setBackground(backgroundPix);
++#endif
+ screensaverWindow->show();
+ screensaverWindow->activateWindow();
+ connect(screensaverWindow, SIGNAL(hidden()), this, SLOT(getFocus()));
+@@ -244,14 +256,52 @@ void UnlockApp::desktopResized()
+ }
+ // random state update, actually rather required on init only
+ QMetaObject::invokeMethod(this, "getFocus", Qt::QueuedConnection);
++ // getFocus on the next event cycle does not work as expected for multiple views
++ // if there's no screensaver, hiding it won't happen and thus not trigger getFocus either
++ // so we call it again in a few miliseconds - the value is nearly random but "must cross some event cycles"
++ // while 150ms worked for me, 250ms gets us a bit more padding without being notable to a human user
++ if (nScreens > 1 && m_screensaverWindows.isEmpty()) {
++ QTimer::singleShot(250, this, SLOT(getFocus()));
++ }
+ capsLocked();
+ }
+
+ void UnlockApp::getFocus()
+ {
+- if (!m_views.isEmpty()) {
+- m_views.first()->activateWindow();
++ if (m_views.isEmpty()) {
++ return;
+ }
++ QWidget *w = 0;
++ // this loop is required to make the qml/graphicsscene properly handle the shared keyboard input
++ // ie. "type something into the box of every greeter"
++ foreach (QDeclarativeView *view, m_views) {
++ view->activateWindow();
++ view->grabKeyboard();
++ view->setFocus(Qt::OtherFocusReason);
++ }
++ // determine which window should actually be active and have the real input focus/grab
++ foreach (QDeclarativeView *view, m_views) {
++ if (view->underMouse()) {
++ w = view;
++ break;
++ }
++ }
++ if (!w) { // try harder
++ foreach (QDeclarativeView *view, m_views) {
++ if (view->geometry().contains(QCursor::pos())) {
++ w = view;
++ break;
++ }
++ }
++ }
++ if (!w) { // fallback solution
++ w = m_views.first();
++ }
++ // activate window and grab input to be sure it really ends up there.
++ // focus setting is still required for proper internal QWidget state (and eg. visual reflection)
++ w->grabKeyboard();
++ w->activateWindow();
++ w->setFocus(Qt::OtherFocusReason);
+ }
+
+ void UnlockApp::setLockedPropertyOnViews()
+@@ -354,14 +404,15 @@ bool UnlockApp::eventFilter(QObject *obj, QEvent *event)
+
+ static bool ignoreNextEscape = false;
+ if (event->type() == QEvent::KeyPress) { // react if saver is visible
+- bool saverVisible = false;
++ bool saverVisible = !m_screensaverWindows.isEmpty();
+ foreach (ScreenSaverWindow *screensaverWindow, m_screensaverWindows) {
+- if (screensaverWindow->isVisible()) {
+- saverVisible = true;
++ if (!screensaverWindow->isVisible()) {
++ saverVisible = false;
+ break;
+ }
+ }
+ if (!saverVisible) {
++ shareEvent(event, qobject_cast<QDeclarativeView*>(obj));
+ return false; // we don't care
+ }
+ ignoreNextEscape = bool(static_cast<QKeyEvent *>(event)->key() == Qt::Key_Escape);
+@@ -378,6 +429,7 @@ bool UnlockApp::eventFilter(QObject *obj, QEvent *event)
+ return false;
+ }
+ if (ke->key() != Qt::Key_Escape) {
++ shareEvent(event, qobject_cast<QDeclarativeView*>(obj));
+ return false; // irrelevant
+ }
+ if (ignoreNextEscape) {
+@@ -428,6 +480,34 @@ void UnlockApp::capsLocked()
+ }
+ }
+
++/*
++ * This function forwards an event from one greeter window to all others
++ * It's used to have the keyboard operate on all greeter windows (on every screen)
++ * at once so that the user gets visual feedback on the screen he's looking at -
++ * even if the focus is actually on a powered off screen.
++ */
++
++void UnlockApp::shareEvent(QEvent *e, QDeclarativeView *from)
++{
++ // from can be NULL any time (because the parameter is passed as qobject_cast)
++ // m_views.contains(from) is atm. supposed to be true but required if any further
++ // QDeclarativeViews are added (which are not part of m_views)
++ // this makes "from" an optimization (nullptr check aversion)
++ if (from && m_views.contains(from)) {
++ // NOTICE any recursion in the event sharing will prevent authentication on multiscreen setups!
++ // Any change in regarded event processing shall be tested thoroughly!
++ removeEventFilter(this); // prevent recursion!
++ const bool accepted = e->isAccepted(); // store state
++ foreach (QDeclarativeView *view, m_views) {
++ if (view != from) {
++ QApplication::sendEvent(view, e);
++ e->setAccepted(accepted);
++ }
++ }
++ installEventFilter(this);
++ }
++}
++
+ } // namespace
+
+ #include "greeterapp.moc"
+diff --git a/ksmserver/screenlocker/greeter/greeterapp.h b/ksmserver/screenlocker/greeter/greeterapp.h
+index 76b9824..8b79188 100644
+--- a/ksmserver/screenlocker/greeter/greeterapp.h
++++ b/ksmserver/screenlocker/greeter/greeterapp.h
+@@ -63,6 +63,7 @@ private Q_SLOTS:
+ private:
+ void initialize();
+ void capsLocked();
++ void shareEvent(QEvent *e, QDeclarativeView *from);
+
+ QString m_mainQmlPath;
+ QList<QDeclarativeView*> m_views;
+--
+1.8.4.4
+