From 511c81f3b376f326cd0f33c222b3f4b6e9a26aa4 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Sep 22 2014 13:07:27 +0000 Subject: import kde-workspace-4.10.5-21.el7 --- diff --git a/SOURCES/kde-workspace-4.10.5-bz#1043686-cpp.patch b/SOURCES/kde-workspace-4.10.5-bz#1043686-cpp.patch new file mode 100644 index 0000000..500a623 --- /dev/null +++ b/SOURCES/kde-workspace-4.10.5-bz#1043686-cpp.patch @@ -0,0 +1,15 @@ +diff -up kde-workspace-4.10.5/kcontrol/krdb/krdb.cpp.krdb kde-workspace-4.10.5/kcontrol/krdb/krdb.cpp +--- kde-workspace-4.10.5/kcontrol/krdb/krdb.cpp.krdb 2013-06-28 19:10:44.184424737 +0200 ++++ kde-workspace-4.10.5/kcontrol/krdb/krdb.cpp 2014-07-16 17:22:30.084547381 +0200 +@@ -538,9 +539,9 @@ void runRdb( uint flags ) + + KProcess proc; + #ifndef NDEBUG +- proc << "xrdb" << "-merge" << tmpFile.fileName(); ++ proc << "xrdb" << "-cpp" << "/bin/cpp" << "-merge" << tmpFile.fileName(); + #else +- proc << "xrdb" << "-quiet" << "-merge" << tmpFile.fileName(); ++ proc << "xrdb" << "-cpp" << "/bin/cpp" << "-quiet" << "-merge" << tmpFile.fileName(); + #endif + proc.execute(); + diff --git a/SOURCES/kde-workspace-4.10.5-bz#1060058.patch b/SOURCES/kde-workspace-4.10.5-bz#1060058.patch new file mode 100644 index 0000000..ab3b816 --- /dev/null +++ b/SOURCES/kde-workspace-4.10.5-bz#1060058.patch @@ -0,0 +1,14 @@ +diff -up kde-workspace-4.10.5/libs/plasmaclock/clockapplet.cpp.orig kde-workspace-4.10.5/libs/plasmaclock/clockapplet.cpp +--- kde-workspace-4.10.5/libs/plasmaclock/clockapplet.cpp.orig 2014-08-18 14:20:18.050240750 +0200 ++++ kde-workspace-4.10.5/libs/plasmaclock/clockapplet.cpp 2014-08-18 14:42:14.695048549 +0200 +@@ -373,7 +373,9 @@ void ClockApplet::createConfigurationInt + + QWidget *generalWidget = new QWidget(); + d->generalUi.setupUi(generalWidget); ++#ifdef JOVIE_FOUND + parent->addPage(generalWidget, i18nc("General configuration page", "General"), Applet::icon()); ++#endif + + d->generalUi.intervalCombo->addItem(i18nc("@inmenu interval between speaking clock", "Never"), QVariant(0)); + d->generalUi.intervalCombo->addItem(i18nc("@inmenu interval between speaking clock", "Every minute"), QVariant(1)); +diff -up kde-workspace-4.10.5/libs/plasmaclock/generalConfig.ui.orig kde-workspace-4.10.5/libs/plasmaclock/generalConfig.ui diff --git a/SOURCES/kde-workspace-4.10.5-solid-bz#1109987.patch b/SOURCES/kde-workspace-4.10.5-solid-bz#1109987.patch new file mode 100644 index 0000000..75272b5 --- /dev/null +++ b/SOURCES/kde-workspace-4.10.5-solid-bz#1109987.patch @@ -0,0 +1,67 @@ +commit 775a99e8bc1e9c5e277ff17a84a406227a5a32fb +Author: Emmanuel Pescosta +Date: Tue Jun 17 17:35:19 2014 +0200 + + Consider additional batteries for power management (when the critical battery timer is running) + + After resuming from suspend, all batteries are added + to powerdevil. When a battery, with charge lower or + equal than the critical charge percentage is added, the + critical battery timer will be started. + + In the current version the critical battery timeout can + only be interrupted by plugging in AC. + + But if the system has more than one battery, the global + charge percentage can be greater than the critical charge + percentage and so the system shouldn't suspend. To achive + this behaviour, we calculate the global charge percentage + whenever a new battery was added and if the critical + battery timer is running and the global charge is high + enough, we stop the timer. + + Also we use the already calculated global charge percentage + for the battery charge percentage notification instead of + the charge of each individual battery. + + With this patch, the user can not only interrupt the critical + timer by plugging in the AC but also by plugging in a new or + additional battery (if the battery has enough charge). + + Note: The 30 sec timeout message will still popup. + + Tested with a Thinkpad T440s (two batteries) + + @Philipp Paris: Thanks for testing! + + BUG: 329537 + BUG: 325707 + FIXED-IN: 4.11.11 + REVIEW: 118801 + +diff --git a/powerdevil/daemon/powerdevilcore.cpp b/powerdevil/daemon/powerdevilcore.cpp +index 76e1b82..d096d74 100644 +--- a/powerdevil/daemon/powerdevilcore.cpp ++++ b/powerdevil/daemon/powerdevilcore.cpp +@@ -456,8 +456,20 @@ void Core::onDeviceAdded(const QString& udi) + } + m_loadedBatteriesUdi.append(udi); + ++ // Compute the current global percentage ++ int globalChargePercent = 0; ++ for (QHash::const_iterator i = m_batteriesPercent.constBegin(); i != m_batteriesPercent.constEnd(); ++i) { ++ globalChargePercent += i.value(); ++ } ++ ++ // If a new battery has been added, let's clear some pending suspend actions if the new global batteries percentage is ++ // higher than the battery low level. (See bug 329537) ++ if (m_criticalBatteryTimer->isActive() && globalChargePercent > PowerDevilSettings::batteryCriticalLevel()) { ++ m_criticalBatteryTimer->stop(); ++ } ++ + // So we get a "Battery is low" notification directly on system startup if applicable +- emitBatteryChargePercentNotification(b->chargePercent(), 100); ++ emitBatteryChargePercentNotification(globalChargePercent, 100); + } + + void Core::onDeviceRemoved(const QString& udi) diff --git a/SOURCES/kde-workspace-4.11-bz#1040678.patch b/SOURCES/kde-workspace-4.11-bz#1040678.patch new file mode 100644 index 0000000..f016ba2 --- /dev/null +++ b/SOURCES/kde-workspace-4.11-bz#1040678.patch @@ -0,0 +1,22 @@ +commit 293b9296bef4920c42eb96380e24a8fe42729b1b +Author: Thomas Lübking +Date: Wed Jul 31 12:14:13 2013 +0200 + + desk-grid: bind sc editor keyChange to kcm changed + + BUG: 316177 + FIXED-IN: 4.11 + REVIEW: 111812 + +diff --git a/kwin/effects/desktopgrid/desktopgrid_config.cpp b/kwin/effects/desktopgrid/desktopgrid_config.cpp +index 45fd205..a3ba77a 100644 +--- a/kwin/effects/desktopgrid/desktopgrid_config.cpp ++++ b/kwin/effects/desktopgrid/desktopgrid_config.cpp +@@ -77,6 +77,7 @@ DesktopGridEffectConfig::DesktopGridEffectConfig(QWidget* parent, const QVariant + addConfig(DesktopGridConfig::self(), m_ui); + connect(m_ui->kcfg_LayoutMode, SIGNAL(currentIndexChanged(int)), this, SLOT(layoutSelectionChanged())); + connect(m_ui->desktopNameAlignmentCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); ++ connect(m_ui->shortcutEditor, SIGNAL(keyChange()), this, SLOT(changed())); + + load(); + layoutSelectionChanged(); diff --git a/SOURCES/kde-workspace-4.11-bz#1090492.patch b/SOURCES/kde-workspace-4.11-bz#1090492.patch new file mode 100644 index 0000000..b381de0 --- /dev/null +++ b/SOURCES/kde-workspace-4.11-bz#1090492.patch @@ -0,0 +1,23 @@ +diff --git a/libs/plasmaclock/calendartable.cpp b/libs/plasmaclock/calendartable.cpp +index 9361a6a..5cba031 100644 +--- a/libs/plasmaclock/calendartable.cpp ++++ b/libs/plasmaclock/calendartable.cpp +@@ -101,6 +101,7 @@ class CalendarTablePrivate + delayedPopulationTimer->setInterval(0); + delayedPopulationTimer->setSingleShot(true); + QObject::connect(delayedPopulationTimer, SIGNAL(timeout()), q, SLOT(populateCalendar())); ++ QObject::connect(KGlobalSettings::self(), SIGNAL(settingsChanged(int)), q, SLOT(settingsChanged(int))); + + setDate(initialDate); + } +@@ -844,6 +845,10 @@ void CalendarTablePrivate::settingsChanged(int category) + } + + calendar = KGlobal::locale()->calendar(); ++ setCalendar(calendar); ++ // Signal out date change so any dependents will update as well ++ emit q->dateChanged(q->date(), q->date()); ++ emit q->dateChanged(q->date()); + q->update(); + } + diff --git a/SOURCES/kde-workspace-4.11-bz#1109936.patch b/SOURCES/kde-workspace-4.11-bz#1109936.patch new file mode 100644 index 0000000..f3f1c9c --- /dev/null +++ b/SOURCES/kde-workspace-4.11-bz#1109936.patch @@ -0,0 +1,2129 @@ +diff --git a/kwin/composite.cpp b/kwin/composite.cpp +index ea540a4..e179b8b 100644 +--- a/kwin/composite.cpp ++++ b/kwin/composite.cpp +@@ -389,7 +389,7 @@ void Compositor::slotReinitialize() + + // Update any settings that can be set in the compositing kcm. + #ifdef KWIN_BUILD_SCREENEDGES +- Workspace::self()->screenEdge()->update(); ++ Workspace::self()->screenEdge()->recreateEdges(); + #endif + // Restart compositing + finish(); +diff --git a/kwin/desktoplayout.cpp b/kwin/desktoplayout.cpp +index f275782..5470eab 100644 +--- a/kwin/desktoplayout.cpp ++++ b/kwin/desktoplayout.cpp +@@ -53,6 +53,7 @@ void Workspace::updateDesktopLayout() + m_screenEdge.reserveDesktopSwitching(true, m_screenEdgeOrientation); + } + #endif ++ + } + + void Workspace::setNETDesktopLayout(Qt::Orientation orientation, int width, int height, +diff --git a/kwin/effects.cpp b/kwin/effects.cpp +index 112c814..8e87f10 100644 +--- a/kwin/effects.cpp ++++ b/kwin/effects.cpp +@@ -1108,28 +1108,30 @@ QPoint EffectsHandlerImpl::cursorPos() const + void EffectsHandlerImpl::checkElectricBorder(const QPoint &pos, Time time) + { + #ifdef KWIN_BUILD_SCREENEDGES +- Workspace::self()->screenEdge()->check(pos, time); ++ Workspace::self()->screenEdge()->check(pos, QDateTime::fromMSecsSinceEpoch(time)); + #else + Q_UNUSED(pos) + Q_UNUSED(time) + #endif + } + +-void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border) ++void EffectsHandlerImpl::reserveElectricBorder(ElectricBorder border, Effect *effect) + { + #ifdef KWIN_BUILD_SCREENEDGES +- Workspace::self()->screenEdge()->reserve(border); ++ Workspace::self()->screenEdge()->reserve(border, effect, "borderActivated"); + #else + Q_UNUSED(border) ++ Q_UNUSED(effect) + #endif + } + +-void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border) ++void EffectsHandlerImpl::unreserveElectricBorder(ElectricBorder border, Effect *effect) + { + #ifdef KWIN_BUILD_SCREENEDGES +- Workspace::self()->screenEdge()->unreserve(border); ++ Workspace::self()->screenEdge()->unreserve(border, effect); + #else + Q_UNUSED(border) ++ Q_UNUSED(effect) + #endif + } + +diff --git a/kwin/effects.h b/kwin/effects.h +index d985de4..2a56cdd 100644 +--- a/kwin/effects.h ++++ b/kwin/effects.h +@@ -140,8 +140,8 @@ public: + virtual void checkInputWindowStacking(); + + virtual void checkElectricBorder(const QPoint &pos, Time time); +- virtual void reserveElectricBorder(ElectricBorder border); +- virtual void unreserveElectricBorder(ElectricBorder border); ++ virtual void reserveElectricBorder(ElectricBorder border, Effect *effect); ++ virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect); + virtual void reserveElectricBorderSwitching(bool reserve, Qt::Orientations o); + + virtual unsigned long xrenderBufferPicture(); +diff --git a/kwin/effects/cube/cube.cpp b/kwin/effects/cube/cube.cpp +index 3fffbd0..840bcf0 100644 +--- a/kwin/effects/cube/cube.cpp ++++ b/kwin/effects/cube/cube.cpp +@@ -122,13 +122,13 @@ void CubeEffect::reconfigure(ReconfigureFlags) + { + CubeConfig::self()->readConfig(); + foreach (ElectricBorder border, borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, borderActivateCylinder) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, borderActivateSphere) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + borderActivate.clear(); + borderActivateCylinder.clear(); +@@ -138,21 +138,21 @@ void CubeEffect::reconfigure(ReconfigureFlags) + borderList = CubeConfig::borderActivate(); + foreach (int i, borderList) { + borderActivate.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + borderList.clear(); + borderList.append(int(ElectricNone)); + borderList = CubeConfig::borderActivateCylinder(); + foreach (int i, borderList) { + borderActivateCylinder.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + borderList.clear(); + borderList.append(int(ElectricNone)); + borderList = CubeConfig::borderActivateSphere(); + foreach (int i, borderList) { + borderActivateSphere.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + + cubeOpacity = (float)CubeConfig::opacity() / 100.0f; +@@ -218,13 +218,13 @@ void CubeEffect::reconfigure(ReconfigureFlags) + CubeEffect::~CubeEffect() + { + foreach (ElectricBorder border, borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, borderActivateCylinder) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, borderActivateSphere) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + delete wallpaper; + delete capTexture; +diff --git a/kwin/effects/desktopgrid/desktopgrid.cpp b/kwin/effects/desktopgrid/desktopgrid.cpp +index 61c814e..826ec9b 100644 +--- a/kwin/effects/desktopgrid/desktopgrid.cpp ++++ b/kwin/effects/desktopgrid/desktopgrid.cpp +@@ -90,7 +90,7 @@ DesktopGridEffect::DesktopGridEffect() + DesktopGridEffect::~DesktopGridEffect() + { + foreach (ElectricBorder border, borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + QHash< DesktopButtonsView*, EffectWindow* >::iterator i = m_desktopButtonsViews.begin(); + while (i != m_desktopButtonsViews.end()) { +@@ -105,12 +105,12 @@ void DesktopGridEffect::reconfigure(ReconfigureFlags) + DesktopGridConfig::self()->readConfig(); + + foreach (ElectricBorder border, borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + borderActivate.clear(); + foreach (int i, DesktopGridConfig::borderActivate()) { + borderActivate.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + + // TODO: rename zoomDuration to duration +diff --git a/kwin/effects/flipswitch/flipswitch.cpp b/kwin/effects/flipswitch/flipswitch.cpp +index 445405e..bb92216 100644 +--- a/kwin/effects/flipswitch/flipswitch.cpp ++++ b/kwin/effects/flipswitch/flipswitch.cpp +@@ -80,10 +80,10 @@ FlipSwitchEffect::FlipSwitchEffect() + FlipSwitchEffect::~FlipSwitchEffect() + { + foreach (ElectricBorder border, m_borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, m_borderActivateAll) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + delete m_captionFrame; + } +@@ -97,20 +97,20 @@ void FlipSwitchEffect::reconfigure(ReconfigureFlags) + { + FlipSwitchConfig::self()->readConfig(); + foreach (ElectricBorder border, m_borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, m_borderActivateAll) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + m_borderActivate.clear(); + m_borderActivateAll.clear(); + foreach (int i, FlipSwitchConfig::borderActivate()) { + m_borderActivate.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + foreach (int i, FlipSwitchConfig::borderActivateAll()) { + m_borderActivateAll.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + m_tabbox = FlipSwitchConfig::tabBox(); + m_tabboxAlternative = FlipSwitchConfig::tabBoxAlternative(); +diff --git a/kwin/effects/presentwindows/presentwindows.cpp b/kwin/effects/presentwindows/presentwindows.cpp +index 79baadb..59eacca 100755 +--- a/kwin/effects/presentwindows/presentwindows.cpp ++++ b/kwin/effects/presentwindows/presentwindows.cpp +@@ -116,10 +116,10 @@ PresentWindowsEffect::~PresentWindowsEffect() + XDeleteProperty(display(), rootWindow(), m_atomWindows); + effects->registerPropertyType(m_atomWindows, false); + foreach (ElectricBorder border, m_borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, m_borderActivateAll) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + delete m_filterFrame; + delete m_closeView; +@@ -129,24 +129,24 @@ void PresentWindowsEffect::reconfigure(ReconfigureFlags) + { + PresentWindowsConfig::self()->readConfig(); + foreach (ElectricBorder border, m_borderActivate) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + foreach (ElectricBorder border, m_borderActivateAll) { +- effects->unreserveElectricBorder(border); ++ effects->unreserveElectricBorder(border, this); + } + m_borderActivate.clear(); + m_borderActivateAll.clear(); + foreach (int i, PresentWindowsConfig::borderActivate()) { + m_borderActivate.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + foreach (int i, PresentWindowsConfig::borderActivateAll()) { + m_borderActivateAll.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + foreach (int i, PresentWindowsConfig::borderActivateClass()) { + m_borderActivateClass.append(ElectricBorder(i)); +- effects->reserveElectricBorder(ElectricBorder(i)); ++ effects->reserveElectricBorder(ElectricBorder(i), this); + } + m_layoutMode = PresentWindowsConfig::layoutMode(); + m_showCaptions = PresentWindowsConfig::drawWindowCaptions(); +diff --git a/kwin/geometry.cpp b/kwin/geometry.cpp +index 5a0eae1..5344ffe 100644 +--- a/kwin/geometry.cpp ++++ b/kwin/geometry.cpp +@@ -77,7 +77,7 @@ void Workspace::desktopResized() + updateClientArea(); + saveOldScreenSizes(); // after updateClientArea(), so that one still uses the previous one + #ifdef KWIN_BUILD_SCREENEDGES +- m_screenEdge.update(true); ++ m_screenEdge.recreateEdges(); + #endif + if (effects) { + static_cast(effects)->desktopResized(geom.size()); +@@ -2589,9 +2589,7 @@ bool Client::startMoveResize() + Notify::raise(isResize() ? Notify::ResizeStart : Notify::MoveStart); + emit clientStartUserMovedResized(this); + #ifdef KWIN_BUILD_SCREENEDGES +- if (options->electricBorders() == Options::ElectricMoveOnly || +- options->electricBorderMaximize() || +- options->electricBorderTiling()) ++ if (workspace()->screenEdge()->isDesktopSwitchingMovingClients()) + workspace()->screenEdge()->reserveDesktopSwitching(true, Qt::Vertical|Qt::Horizontal); + #endif + if (fakeMove) // fix geom_restore position - it HAS to happen at the end, ie. when all moving is set up. inline call will lock focus!! +@@ -2599,37 +2597,6 @@ bool Client::startMoveResize() + return true; + } + +-static ElectricBorder electricBorderFromMode(QuickTileMode mode) +-{ +- // special case, currently maxmizing is done from the electric top corner +- if (mode == QuickTileMaximize) +- return ElectricTop; +- +- // sanitize the mode, ie. simplify "invalid" combinations +- if ((mode & QuickTileHorizontal) == QuickTileHorizontal) +- mode &= ~QuickTileHorizontal; +- if ((mode & QuickTileVertical) == QuickTileVertical) +- mode &= ~QuickTileVertical; +- +- if (mode == QuickTileLeft) +- return ElectricLeft; +- if (mode == QuickTileRight) +- return ElectricRight; +- if (mode == (QuickTileTop|QuickTileLeft)) +- return ElectricTopLeft; +- if (mode == (QuickTileTop|QuickTileRight)) +- return ElectricTopRight; +- if (mode == (QuickTileBottom|QuickTileLeft)) +- return ElectricBottomLeft; +- if (mode == (QuickTileBottom|QuickTileRight)) +- return ElectricBottomRight; +- if (mode == QuickTileTop) +- return ElectricTop; +- if (mode == QuickTileBottom) +- return ElectricBottom; +- return ElectricNone; +-} +- + void Client::finishMoveResize(bool cancel) + { + const bool wasResize = isResize(); // store across leaveMoveResize +@@ -2658,14 +2625,6 @@ void Client::finishMoveResize(bool cancel) + + if (isElectricBorderMaximizing()) { + setQuickTileMode(electricMode); +- const ElectricBorder border = electricBorderFromMode(electricMode); +- if (border == ElectricNone) +- kDebug(1212) << "invalid electric mode" << electricMode << "leading to invalid array access,\ +- this should not have happened!"; +-#ifdef KWIN_BUILD_SCREENEDGES +- else +- workspace()->screenEdge()->restoreSize(border); +-#endif + electricMaximizing = false; + workspace()->outline()->hide(); + } else if (!cancel) { +@@ -2713,9 +2672,7 @@ void Client::leaveMoveResize() + syncRequest.timeout = NULL; + #endif + #ifdef KWIN_BUILD_SCREENEDGES +- if (options->electricBorders() == Options::ElectricMoveOnly || +- options->electricBorderMaximize() || +- options->electricBorderTiling()) ++ if (workspace()->screenEdge()->isDesktopSwitchingMovingClients()) + workspace()->screenEdge()->reserveDesktopSwitching(false, Qt::Vertical|Qt::Horizontal); + #endif + } +@@ -3082,7 +3039,7 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) + + if (isMove()) { + #ifdef KWIN_BUILD_SCREENEDGES +- workspace()->screenEdge()->check(globalPos, xTime()); ++ workspace()->screenEdge()->check(globalPos, QDateTime::fromMSecsSinceEpoch(xTime())); + #endif + } + } +diff --git a/kwin/libkwineffects/kwineffects.h b/kwin/libkwineffects/kwineffects.h +index f6bb636..731869f 100644 +--- a/kwin/libkwineffects/kwineffects.h ++++ b/kwin/libkwineffects/kwineffects.h +@@ -438,8 +438,6 @@ public: + virtual void windowInputMouseEvent(Window w, QEvent* e); + virtual void grabbedKeyboardEvent(QKeyEvent* e); + +- virtual bool borderActivated(ElectricBorder border); +- + /** + * Overwrite this method to indicate whether your effect will be doing something in + * the next frame to be rendered. If the method returns @c false the effect will be +@@ -496,6 +494,9 @@ public: + **/ + static void setPositionTransformations(WindowPaintData& data, QRect& region, EffectWindow* w, + const QRect& r, Qt::AspectRatioMode aspect); ++ ++public Q_SLOTS: ++ virtual bool borderActivated(ElectricBorder border); + }; + + +@@ -653,8 +654,8 @@ public: + virtual void stopMousePolling() = 0; + + virtual void checkElectricBorder(const QPoint &pos, Time time) = 0; +- virtual void reserveElectricBorder(ElectricBorder border) = 0; +- virtual void unreserveElectricBorder(ElectricBorder border) = 0; ++ virtual void reserveElectricBorder(ElectricBorder border, Effect *effect) = 0; ++ virtual void unreserveElectricBorder(ElectricBorder border, Effect *effect) = 0; + virtual void reserveElectricBorderSwitching(bool reserve, Qt::Orientations o) = 0; + + // functions that allow controlling windows/desktop +diff --git a/kwin/screenedge.cpp b/kwin/screenedge.cpp +index 80a3931..cc114c2 100644 +--- a/kwin/screenedge.cpp ++++ b/kwin/screenedge.cpp +@@ -41,14 +41,415 @@ along with this program. If not, see . + #include + #include + #include ++#include ++#include + + namespace KWin { + ++ // Mouse should not move more than this many pixels ++static const int DISTANCE_RESET = 30; ++ ++Edge::Edge(ScreenEdge *parent) ++ : QObject(parent) ++ , m_edges(parent) ++ , m_border(ElectricNone) ++ , m_action(ElectricActionNone) ++ , m_reserved(0) ++ , m_blocked(false) ++{ ++} ++ ++Edge::~Edge() ++{ ++} ++ ++void Edge::reserve() ++{ ++ m_reserved++; ++ if (m_reserved == 1) { ++ activate(); ++ } ++} ++ ++void Edge::reserve(QObject *object, const char *slot) ++{ ++ connect(object, SIGNAL(destroyed(QObject*)), SLOT(unreserve(QObject*))); ++ m_callBacks.insert(object, QByteArray(slot)); ++ reserve(); ++} ++ ++void Edge::unreserve() ++{ ++ m_reserved--; ++ if (m_reserved == 0) { ++ deactivate(); ++ } ++} ++ ++void Edge::unreserve(QObject *object) ++{ ++ if (m_callBacks.contains(object)) { ++ m_callBacks.remove(object); ++ disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(unreserve(QObject*))); ++ unreserve(); ++ } ++} ++ ++bool Edge::triggersFor(const QPoint &cursorPos) const ++{ ++ if (isBlocked()) { ++ return false; ++ } ++ if (!m_geometry.contains(cursorPos)) { ++ return false; ++ } ++ if (isLeft() && cursorPos.x() != m_geometry.x()) { ++ return false; ++ } ++ if (isRight() && cursorPos.x() != (m_geometry.x() + m_geometry.width() -1)) { ++ return false; ++ } ++ if (isTop() && cursorPos.y() != m_geometry.y()) { ++ return false; ++ } ++ if (isBottom() && cursorPos.y() != (m_geometry.y() + m_geometry.height() -1)) { ++ return false; ++ } ++ return true; ++} ++ ++void Edge::check(const QPoint &cursorPos, const QDateTime &triggerTime, bool forceNoPushback) ++{ ++ if (!triggersFor(cursorPos)) { ++ return; ++ } ++ // no pushback so we have to activate at once ++ bool directActivate = forceNoPushback || edges()->cursorPushBackDistance().isNull(); ++ if (directActivate || canActivate(cursorPos, triggerTime)) { ++ m_lastTrigger = triggerTime; ++ m_lastReset = QDateTime(); // invalidate ++ handle(cursorPos); ++ } else { ++ pushCursorBack(cursorPos); ++ } ++ m_triggeredPoint = cursorPos; ++} ++ ++bool Edge::canActivate(const QPoint &cursorPos, const QDateTime &triggerTime) ++{ ++ // we check whether either the timer has explicitly been invalidated (successfull trigger) or is ++ // bigger than the reactivation threshold (activation "aborted", usually due to moving away the cursor ++ // from the corner after successfull activation) ++ // either condition means that "this is the first event in a new attempt" ++ if (!m_lastReset.isValid() || m_lastReset.msecsTo(triggerTime) > edges()->reActivationThreshold()) { ++ m_lastReset = triggerTime; ++ return false; ++ } ++ if (m_lastTrigger.msecsTo(triggerTime) < edges()->reActivationThreshold()) { ++ return false; ++ } ++ if (m_lastReset.msecsTo(triggerTime) < edges()->timeThreshold()) { ++ return false; ++ } ++ // does the check on position make any sense at all? ++ if ((cursorPos - m_triggeredPoint).manhattanLength() > DISTANCE_RESET) { ++ return false; ++ } ++ return true; ++} ++ ++void Edge::handle(const QPoint &cursorPos) ++{ ++ if ((edges()->isDesktopSwitchingMovingClients() && Workspace::self()->getMovingClient()) || ++ (edges()->isDesktopSwitching() && isScreenEdge())) { ++ // always switch desktop in case: ++ // moving a Client and option for switch on client move is enabled ++ // or switch on screen edge is enabled ++ switchDesktop(cursorPos); ++ return; ++ } ++ if (Workspace::self()->getMovingClient()) { ++ // if we are moving a window we don't want to trigger the actions. This just results in ++ // problems, e.g. Desktop Grid activated or screen locker activated which just cannot ++ // work as we hold a grab ++ return; ++ } ++ if (handleAction() || handleByCallback()) { ++ return; ++ } ++ if (edges()->isDesktopSwitching() && isCorner()) { ++ // try again desktop switching in the corder ++ switchDesktop(cursorPos); ++ } ++} ++ ++bool Edge::handleAction() ++{ ++ switch (m_action) { ++ case ElectricActionDashboard: { // Display Plasma dashboard ++ QDBusInterface plasmaApp("org.kde.plasma-desktop", "/App"); ++ plasmaApp.asyncCall("toggleDashboard"); ++ return true; ++ } ++ case ElectricActionShowDesktop: { ++ Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop()); ++ return true; ++ } ++ case ElectricActionLockScreen: { // Lock the screen ++ QDBusInterface screenSaver("org.kde.screensaver", "/ScreenSaver"); ++ screenSaver.asyncCall("Lock"); ++ return true; ++ } ++ default: ++ return false; ++ } ++} ++ ++bool Edge::handleByCallback() ++{ ++ if (m_callBacks.isEmpty()) { ++ return false; ++ } ++ for (QHash::iterator it = m_callBacks.begin(); ++ it != m_callBacks.end(); ++ ++it) { ++ bool retVal = false; ++ QMetaObject::invokeMethod(it.key(), it.value().constData(), Q_RETURN_ARG(bool, retVal), Q_ARG(ElectricBorder, m_border)); ++ if (retVal) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++void Edge::switchDesktop(const QPoint& cursorPos) ++{ ++ QPoint pos(cursorPos); ++ const uint oldDesktop = Workspace::self()->currentDesktop(); ++ uint desktop = oldDesktop; ++ const int OFFSET = 2; ++ if (isLeft()) { ++ const uint interimDesktop = desktop; ++ desktop = Workspace::self()->desktopToLeft(desktop, options->isRollOverDesktops()); ++ if (desktop != interimDesktop) ++ pos.setX(displayWidth() - 1 - OFFSET); ++ } else if (isRight()) { ++ const uint interimDesktop = desktop; ++ desktop = Workspace::self()->desktopToRight(desktop, options->isRollOverDesktops()); ++ if (desktop != interimDesktop) ++ pos.setX(OFFSET); ++ } ++ if (isTop()) { ++ const uint interimDesktop = desktop; ++ desktop = Workspace::self()->desktopAbove(desktop, options->isRollOverDesktops()); ++ if (desktop != interimDesktop) ++ pos.setY(displayHeight() - 1 - OFFSET); ++ } else if (isBottom()) { ++ const uint interimDesktop = desktop; ++ desktop = Workspace::self()->desktopBelow(desktop, options->isRollOverDesktops()); ++ if (desktop != interimDesktop) ++ pos.setY(OFFSET); ++ } ++ if (Client *c = Workspace::self()->getMovingClient()) { ++ if (c->rules()->checkDesktop(desktop) != int(desktop)) { ++ // user attempts to move a client to another desktop where it is ruleforced to not be ++ return; ++ } ++ } ++ Workspace::self()->setCurrentDesktop(desktop); ++ if (desktop != oldDesktop) { ++ QCursor::setPos(pos); ++ } ++} ++ ++void Edge::pushCursorBack(const QPoint& cursorPos) ++{ ++ int x = cursorPos.x(); ++ int y = cursorPos.y(); ++ const QSize &distance = edges()->cursorPushBackDistance(); ++ if (isLeft()) { ++ x += distance.width(); ++ } ++ if (isRight()) { ++ x -= distance.width(); ++ } ++ if (isTop()) { ++ y += distance.height(); ++ } ++ if (isBottom()) { ++ y -= distance.height(); ++ } ++ QCursor::setPos(x, y); ++} ++ ++void Edge::setGeometry(const QRect &geometry) ++{ ++ if (m_geometry == geometry) { ++ return; ++ } ++ m_geometry = geometry; ++ int x = m_geometry.x(); ++ int y = m_geometry.y(); ++ int width = m_geometry.width(); ++ int height = m_geometry.height(); ++ const int size = m_edges->cornerOffset(); ++ if (isCorner()) { ++ if (isRight()) { ++ x = x - size +1; ++ } ++ if (isBottom()) { ++ y = y - size +1; ++ } ++ width = size; ++ height = size; ++ } else { ++ if (isLeft()) { ++ y += size + 1; ++ width = size; ++ height = height - size * 2; ++ } else if (isRight()) { ++ x = x - size + 1; ++ y += size; ++ width = size; ++ height = height - size * 2; ++ } else if (isTop()) { ++ x += size; ++ width = width - size * 2; ++ height = size; ++ } else if (isBottom()) { ++ x += size; ++ y = y - size +1; ++ width = width - size * 2; ++ height = size; ++ } ++ } ++ doGeometryUpdate(); ++} ++ ++void Edge::checkBlocking() ++{ ++ if (isCorner()) { ++ return; ++ } ++ bool newValue = false; ++ if (Client *client = Workspace::self()->activeClient()) { ++ newValue = client->isFullScreen() && client->geometry().contains(m_geometry.center()); ++ } ++ if (newValue == m_blocked) { ++ return; ++ } ++ m_blocked = newValue; ++ doUpdateBlocking(); ++} ++ ++void Edge::doUpdateBlocking() ++{ ++} ++ ++void Edge::doGeometryUpdate() ++{ ++} ++ ++void Edge::activate() ++{ ++} ++ ++void Edge::deactivate() ++{ ++} ++ ++/********************************************************** ++ * ScreenEdge ++ *********************************************************/ ++ ++WindowBasedEdge::WindowBasedEdge(ScreenEdge* parent) ++ : Edge(parent) ++ , m_window(None) ++{ ++} ++ ++WindowBasedEdge::~WindowBasedEdge() ++{ ++} ++ ++void WindowBasedEdge::activate() ++{ ++ createWindow(); ++ doUpdateBlocking(); ++} ++ ++void WindowBasedEdge::deactivate() ++{ ++ if (m_window != None) { ++ XDestroyWindow(display(), m_window); ++ m_window = None; ++ } ++} ++ ++void WindowBasedEdge::createWindow() ++{ ++ if (m_window != None) { ++ return; ++ } ++ ++ XSetWindowAttributes attributes; ++ attributes.override_redirect = True; ++ attributes.event_mask = EnterWindowMask | LeaveWindowMask; ++ unsigned long valuemask = CWOverrideRedirect | CWEventMask; ++ ++ const QRect geom = geometry(); ++ m_window = XCreateWindow(display(), rootWindow(), ++ geom.x(), geom.y(), geom.width(), geom.height(), ++ 0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); ++ XMapWindow(display(), m_window); ++ // Set XdndAware on the windows, so that DND enter events are received (#86998) ++ Atom version = 4; // XDND version ++ XChangeProperty(display(), m_window, atoms->xdnd_aware, XA_ATOM, ++ 32, PropModeReplace, (unsigned char*)(&version), 1); ++} ++ ++void WindowBasedEdge::doGeometryUpdate() ++{ ++ const QRect geom = geometry(); ++ XMoveResizeWindow(display(), m_window, ++ geom.x(), geom.y(), geom.width(), geom.height()); ++} ++ ++void WindowBasedEdge::doUpdateBlocking() ++{ ++ if (!isReserved()) { ++ return; ++ } ++ if (isBlocked()) { ++ XUnmapWindow(display(), m_window); ++ } else { ++ XMapWindow(display(), m_window); ++ } ++} ++ ++/********************************************************** ++ * ScreenEdges ++ *********************************************************/ ++ + ScreenEdge::ScreenEdge() + : QObject(NULL) +- , m_screenEdgeWindows(ELECTRIC_COUNT, None) +- , m_screenEdgeReserved(ELECTRIC_COUNT, 0) ++ , m_desktopSwitching(false) ++ , m_desktopSwitchingMovingClients(false) ++ , m_timeThreshold(0) ++ , m_reactivateThreshold(0) ++ , m_virtualDesktopLayout(0) ++ , m_actionTopLeft(ElectricActionNone) ++ , m_actionTop(ElectricActionNone) ++ , m_actionTopRight(ElectricActionNone) ++ , m_actionRight(ElectricActionNone) ++ , m_actionBottomRight(ElectricActionNone) ++ , m_actionBottom(ElectricActionNone) ++ , m_actionBottomLeft(ElectricActionNone) ++ , m_actionLeft(ElectricActionNone) ++ , m_cornerOffset(0) + { ++ QWidget w; ++ m_cornerOffset = (w.physicalDpiX() + w.physicalDpiY() + 5) / 6; + } + + ScreenEdge::~ScreenEdge() +@@ -57,326 +458,432 @@ ScreenEdge::~ScreenEdge() + + void ScreenEdge::init() + { +- reserveActions(true); +- update(); ++ reconfigure(); ++ updateLayout(); ++ recreateEdges(); ++} ++ ++static ElectricBorderAction electricBorderAction(const QString &name) ++{ ++ QString lowerName = name.toLower(); ++ if (lowerName == "dashboard") { ++ return ElectricActionDashboard; ++ } else if (lowerName == "showdesktop") { ++ return ElectricActionShowDesktop; ++ } else if (lowerName == "lockscreen") { ++ return ElectricActionLockScreen; ++ } else if (lowerName == "preventscreenlocking") { ++ return ElectricActionPreventScreenLocking; ++ } ++ return ElectricActionNone; ++} ++ ++void ScreenEdge::reconfigure() ++{ ++ if (!m_config) { ++ return; ++ } ++ // TODO: migrate settings to a group ScreenEdges ++ KConfigGroup windowsConfig = m_config->group("Windows"); ++ setTimeThreshold(windowsConfig.readEntry("ElectricBorderDelay", 150)); ++ setReActivationThreshold(qMax(timeThreshold() + 50, windowsConfig.readEntry("ElectricBorderCooldown", 350))); ++ int desktopSwitching = windowsConfig.readEntry("ElectricBorders", static_cast(ElectricDisabled)); ++ if (desktopSwitching == ElectricDisabled) { ++ setDesktopSwitching(false); ++ setDesktopSwitchingMovingClients(false); ++ } else if (desktopSwitching == ElectricMoveOnly) { ++ setDesktopSwitching(false); ++ setDesktopSwitchingMovingClients(true); ++ } else if (desktopSwitching == ElectricAlways) { ++ setDesktopSwitching(true); ++ setDesktopSwitchingMovingClients(true); ++ } ++ const int pushBack = windowsConfig.readEntry("ElectricBorderPushbackPixels", 1); ++ m_cursorPushBackDistance = QSize(pushBack, pushBack); ++ ++ KConfigGroup borderConfig = m_config->group("ElectricBorders"); ++ setActionForBorder(ElectricTopLeft, &m_actionTopLeft, ++ electricBorderAction(borderConfig.readEntry("TopLeft", "None"))); ++ setActionForBorder(ElectricTop, &m_actionTop, ++ electricBorderAction(borderConfig.readEntry("Top", "None"))); ++ setActionForBorder(ElectricTopRight, &m_actionTopRight, ++ electricBorderAction(borderConfig.readEntry("TopRight", "None"))); ++ setActionForBorder(ElectricRight, &m_actionRight, ++ electricBorderAction(borderConfig.readEntry("Right", "None"))); ++ setActionForBorder(ElectricBottomRight, &m_actionBottomRight, ++ electricBorderAction(borderConfig.readEntry("BottomRight", "None"))); ++ setActionForBorder(ElectricBottom, &m_actionBottom, ++ electricBorderAction(borderConfig.readEntry("Bottom", "None"))); ++ setActionForBorder(ElectricBottomLeft, &m_actionBottomLeft, ++ electricBorderAction(borderConfig.readEntry("BottomLeft", "None"))); ++ setActionForBorder(ElectricLeft, &m_actionLeft, ++ electricBorderAction(borderConfig.readEntry("Left", "None"))); + } + +-void ScreenEdge::update(bool force) ++void ScreenEdge::setActionForBorder(ElectricBorder border, ElectricBorderAction* oldValue, ElectricBorderAction newValue) + { +- m_screenEdgeTimeFirst = xTime(); +- m_screenEdgeTimeLast = xTime(); +- m_screenEdgeTimeLastTrigger = xTime(); +- m_currentScreenEdge = ElectricNone; +- QRect r = QRect(0, 0, displayWidth(), displayHeight()); +- m_screenEdgeTop = r.top(); +- m_screenEdgeBottom = r.bottom(); +- m_screenEdgeLeft = r.left(); +- m_screenEdgeRight = r.right(); + +- for (int pos = 0; pos < ELECTRIC_COUNT; ++pos) { +- if (force || m_screenEdgeReserved[pos] == 0) { +- if (m_screenEdgeWindows[pos] != None) +- XDestroyWindow(display(), m_screenEdgeWindows[pos]); +- m_screenEdgeWindows[pos] = None; ++ if (*oldValue == newValue) { ++ return; ++ } ++ if (*oldValue == ElectricActionNone) { ++ // have to reserve ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ if ((*it)->border() == border) { ++ (*it)->reserve(); ++ } + } +- if (m_screenEdgeReserved[pos] == 0) { ++ } ++ if (newValue == ElectricActionNone) { ++ // have to unreserve ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ if ((*it)->border() == border) { ++ (*it)->unreserve(); ++ } ++ } ++ } ++ *oldValue = newValue; ++ // update action on all Edges for given border ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ if ((*it)->border() == border) { ++ (*it)->setAction(newValue); ++ } ++ } ++} ++ ++void ScreenEdge::updateLayout() ++{ ++ const QSize desktopMatrix = Workspace::self()->desktopGridSize(); ++ Qt::Orientations newLayout = 0; ++ if (desktopMatrix.width() > 1) { ++ newLayout |= Qt::Horizontal; ++ } ++ if (desktopMatrix.height() > 1) { ++ newLayout |= Qt::Vertical; ++ } ++ if (newLayout == m_virtualDesktopLayout) { ++ return; ++ } ++ if (isDesktopSwitching()) { ++ reserveDesktopSwitching(false, m_virtualDesktopLayout); ++ } ++ m_virtualDesktopLayout = newLayout; ++ if (isDesktopSwitching()) { ++ reserveDesktopSwitching(true, m_virtualDesktopLayout); ++ } ++} ++ ++static bool isLeftScreen(const QRect &screen, const QRect &fullArea) ++{ ++ if (QApplication::desktop()->screenCount() == 1) { ++ return true; ++ } ++ if (screen.x() == fullArea.x()) { ++ return true; ++ } ++ // the screen is also on the left in case of a vertical layout with a second screen ++ // more to the left. In that case no screen ends left of screen's x coord ++ for (int i=0; iscreenCount(); ++i) { ++ const QRect otherGeo = QApplication::desktop()->screenGeometry(i); ++ if (otherGeo == screen) { ++ // that's our screen to test + continue; + } +- if (m_screenEdgeWindows[pos] != None) ++ if (otherGeo.x() + otherGeo.width() <= screen.x()) { ++ // other screen is completely in the left ++ return false; ++ } ++ } ++ // did not find a screen left of our current screen, so it is the left most ++ return true; ++} ++ ++static bool isRightScreen(const QRect &screen, const QRect &fullArea) ++{ ++ if (QApplication::desktop()->screenCount() == 1) { ++ return true; ++ } ++ if (screen.x() + screen.width() == fullArea.x() + fullArea.width()) { ++ return true; ++ } ++ // the screen is also on the right in case of a vertical layout wit a second screen ++ // more to the right. In that case no screen starts right of this screen ++ for (int i=0; iscreenCount(); ++i) { ++ const QRect otherGeo = QApplication::desktop()->screenGeometry(i); ++ if (otherGeo == screen) { ++ // that's our screen to test + continue; +- XSetWindowAttributes attributes; +- attributes.override_redirect = True; +- attributes.event_mask = EnterWindowMask | LeaveWindowMask; +- unsigned long valuemask = CWOverrideRedirect | CWEventMask; +- int xywh[ELECTRIC_COUNT][4] = { +- { r.left() + 1, r.top(), r.width() - 2, 1 }, // Top +- { r.right(), r.top(), 1, 1 }, // Top-right +- { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc. +- { r.right(), r.bottom(), 1, 1 }, +- { r.left() + 1, r.bottom(), r.width() - 2, 1 }, +- { r.left(), r.bottom(), 1, 1 }, +- { r.left(), r.top() + 1, 1, r.height() - 2 }, +- { r.left(), r.top(), 1, 1 } +- }; +- m_screenEdgeWindows[pos] = XCreateWindow(display(), rootWindow(), +- xywh[pos][0], xywh[pos][1], xywh[pos][2], xywh[pos][3], +- 0, CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); +- XMapWindow(display(), m_screenEdgeWindows[pos]); +- +- // Set XdndAware on the windows, so that DND enter events are received (#86998) +- Atom version = 4; // XDND version +- XChangeProperty(display(), m_screenEdgeWindows[pos], atoms->xdnd_aware, XA_ATOM, +- 32, PropModeReplace, (unsigned char*)(&version), 1); +- } +-} +- +-void ScreenEdge::restoreSize(ElectricBorder border) +-{ +- if (m_screenEdgeWindows[border] == None) +- return; +- QRect r(0, 0, displayWidth(), displayHeight()); +- int xywh[ELECTRIC_COUNT][4] = { +- { r.left() + 1, r.top(), r.width() - 2, 1 }, // Top +- { r.right(), r.top(), 1, 1 }, // Top-right +- { r.right(), r.top() + 1, 1, r.height() - 2 }, // Etc. +- { r.right(), r.bottom(), 1, 1 }, +- { r.left() + 1, r.bottom(), r.width() - 2, 1 }, +- { r.left(), r.bottom(), 1, 1 }, +- { r.left(), r.top() + 1, 1, r.height() - 2 }, +- { r.left(), r.top(), 1, 1 } +- }; +- XMoveResizeWindow(display(), m_screenEdgeWindows[border], +- xywh[border][0], xywh[border][1], xywh[border][2], xywh[border][3]); +-} +- +-void ScreenEdge::reserveActions(bool isToReserve) +-{ +- for (int pos = 0; pos < ELECTRIC_COUNT; ++pos) +- if (options->electricBorderAction(static_cast(pos))) { +- if (isToReserve) +- reserve(static_cast(pos)); +- else +- unreserve(static_cast(pos)); + } ++ if (otherGeo.x() >= screen.x() + screen.width()) { ++ // other screen is completely in the right ++ return false; ++ } ++ } ++ // did not find a screen right of our current screen, so it is the right most ++ return true; + } + +-void ScreenEdge::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o) ++static bool isTopScreen(const QRect &screen, const QRect &fullArea) + { +- if (!o) +- return; +- if (isToReserve) { +- reserve(ElectricTopLeft); +- reserve(ElectricTopRight); +- reserve(ElectricBottomRight); +- reserve(ElectricBottomLeft); +- +- if (o & Qt::Horizontal) { +- reserve(ElectricLeft); +- reserve(ElectricRight); ++ if (QApplication::desktop()->screenCount() == 1) { ++ return true; ++ } ++ if (screen.y() == fullArea.y()) { ++ return true; ++ } ++ // the screen is also top most in case of a horizontal layout with a second screen ++ // more to the top. In that case no screen ends above screen's y cord ++ for (int i=0; iscreenCount(); ++i) { ++ const QRect otherGeo = QApplication::desktop()->screenGeometry(i); ++ if (otherGeo == screen) { ++ // that's our screen to test ++ continue; + } +- if (o & Qt::Vertical) { +- reserve(ElectricTop); +- reserve(ElectricBottom); ++ if (otherGeo.y() + otherGeo.height() <= screen.y()) { ++ // other screen is completely above ++ return false; + } +- } else { +- unreserve(ElectricTopLeft); +- unreserve(ElectricTopRight); +- unreserve(ElectricBottomRight); +- unreserve(ElectricBottomLeft); +- +- if (o & Qt::Horizontal) { +- unreserve(ElectricLeft); +- unreserve(ElectricRight); ++ } ++ // did not find a screen above our current screen, os it is the top most ++ return true; ++} ++ ++static bool isBottomScreen(const QRect &screen, const QRect &fullArea) ++{ ++ if (QApplication::desktop()->screenCount() == 1) { ++ return true; ++ } ++ if (screen.y() + screen.height() == fullArea.y() + fullArea.height()) { ++ return true; ++ } ++ // the screen is also bottom most in case of a horizontal layout with a second screen ++ // more below. In that case no screen starts below screen's y coord + height ++ for (int i=0; iscreenCount(); ++i) { ++ const QRect otherGeo = QApplication::desktop()->screenGeometry(i); ++ if (otherGeo == screen) { ++ // that's our screen to test ++ continue; + } +- if (o & Qt::Vertical) { +- unreserve(ElectricTop); +- unreserve(ElectricBottom); ++ if (otherGeo.y() >= screen.y() + screen.height()) { ++ // other screen is completely below ++ return false; + } + } ++ // did not find a screen below our current screen, so it is the bottom most ++ return true; + } + +-void ScreenEdge::reserve(ElectricBorder border) ++void ScreenEdge::recreateEdges() + { +- if (border == ElectricNone) +- return; +- if (m_screenEdgeReserved[border]++ == 0) +- QTimer::singleShot(0, this, SLOT(update())); ++ QList oldEdges = m_edges; ++ m_edges.clear(); ++ QRect fullArea = QRect(0, 0, displayWidth(), displayHeight()); ++ for (int i = 0, c = QApplication::desktop()->screenCount(); i < c; ++i) { ++ const QRect screen = QApplication::desktop()->screenGeometry(i); ++ if (isLeftScreen(screen, fullArea)) { ++ createVerticalEdge(ElectricLeft, screen, fullArea); ++ } ++ if (isRightScreen(screen, fullArea)) { ++ createVerticalEdge(ElectricRight, screen, fullArea); ++ } ++ if (isTopScreen(screen, fullArea)) { ++ createHorizontalEdge(ElectricTop, screen, fullArea); ++ } ++ if (isBottomScreen(screen, fullArea)) { ++ createHorizontalEdge(ElectricBottom, screen, fullArea); ++ } ++ } ++ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ WindowBasedEdge *edge = *it; ++ for (QList::const_iterator oldIt = oldEdges.constBegin(); ++ oldIt != oldEdges.constEnd(); ++ ++oldIt) { ++ WindowBasedEdge *oldEdge = *oldIt; ++ if (oldEdge->border() != edge->border()) { ++ continue; ++ } ++ const QHash &callbacks = oldEdge->callBacks(); ++ for (QHash::const_iterator callback = callbacks.begin(); ++ callback != callbacks.end(); ++ ++callback) { ++ edge->reserve(callback.key(), callback.value().constData()); ++ } ++ } ++ } ++ qDeleteAll(oldEdges); + } + +-void ScreenEdge::unreserve(ElectricBorder border) ++void ScreenEdge::createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea) + { +- if (border == ElectricNone) ++ if (border != KWin::ElectricRight && border != KWin::ElectricLeft) { + return; +- assert(m_screenEdgeReserved[border] > 0); +- if (--m_screenEdgeReserved[border] == 0) +- QTimer::singleShot(0, this, SLOT(update())); ++ } ++ const int y = screen.y(); ++ const int height = screen.height(); ++ const int x = (border == ElectricLeft) ? screen.x() : screen.x() + screen.width() - 1; ++ if (isTopScreen(screen, fullArea)) { ++ // also top most screen ++ // create top left/right edge ++ const ElectricBorder edge = (border == ElectricLeft) ? ElectricTopLeft : ElectricTopRight; ++ m_edges << createEdge(edge, x, screen.y(), 1, 1); ++ } ++ if (isBottomScreen(screen, fullArea)) { ++ // also bottom most screen ++ // create bottom left/right edge ++ const ElectricBorder edge = (border == ElectricLeft) ? ElectricBottomLeft : ElectricBottomRight; ++ m_edges << createEdge(edge, x, screen.y() + screen.height() - 1, 1, 1); ++ } ++ m_edges << createEdge(border, x, y, 1, height); + } + +-void ScreenEdge::check(const QPoint& pos, Time now, bool forceNoPushback) ++void ScreenEdge::createHorizontalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea) + { +- if ((pos.x() != m_screenEdgeLeft) && +- (pos.x() != m_screenEdgeRight) && +- (pos.y() != m_screenEdgeTop) && +- (pos.y() != m_screenEdgeBottom)) +- return; ++ Q_UNUSED(fullArea) + +- bool have_borders = false; +- for (int i = 0; i < ELECTRIC_COUNT; ++i) +- if (m_screenEdgeWindows[i] != None) +- have_borders = true; +- if (!have_borders) ++ if (border != ElectricTop && border != ElectricBottom) { + return; ++ } ++ const int x = screen.x(); ++ const int width = screen.width(); ++ const int y = (border == ElectricTop) ? screen.y() : screen.y() + screen.height() - 1; ++ m_edges << createEdge(border, x, y, width, 1); ++} + +- Time treshold_set = options->electricBorderDelay(); // Set timeout +- Time treshold_reset = 250; // Reset timeout +- Time treshold_trigger = options->electricBorderCooldown(); // Minimum time between triggers +- int distance_reset = 30; // Mouse should not move more than this many pixels +- int pushback_pixels = forceNoPushback ? 0 : options->electricBorderPushbackPixels(); +- +- ElectricBorder border; +- if (pos.x() == m_screenEdgeLeft && pos.y() == m_screenEdgeTop) +- border = ElectricTopLeft; +- else if (pos.x() == m_screenEdgeRight && pos.y() == m_screenEdgeTop) +- border = ElectricTopRight; +- else if (pos.x() == m_screenEdgeLeft && pos.y() == m_screenEdgeBottom) +- border = ElectricBottomLeft; +- else if (pos.x() == m_screenEdgeRight && pos.y() == m_screenEdgeBottom) +- border = ElectricBottomRight; +- else if (pos.x() == m_screenEdgeLeft) +- border = ElectricLeft; +- else if (pos.x() == m_screenEdgeRight) +- border = ElectricRight; +- else if (pos.y() == m_screenEdgeTop) +- border = ElectricTop; +- else if (pos.y() == m_screenEdgeBottom) +- border = ElectricBottom; +- else +- abort(); +- +- if (m_screenEdgeWindows[border] == None) +- return; ++WindowBasedEdge* ScreenEdge::createEdge(ElectricBorder border, int x, int y, int width, int height) ++{ ++ WindowBasedEdge *edge = new WindowBasedEdge(this); ++ edge->setBorder(border); ++ edge->setGeometry(QRect(x, y, width, height)); ++ const ElectricBorderAction action = actionForEdge(edge); ++ if (action != KWin::ElectricActionNone) { ++ edge->reserve(); ++ edge->setAction(action); ++ } ++ if (isDesktopSwitching()) { ++ if (edge->isCorner()) { ++ edge->reserve(); ++ } else { ++ if ((m_virtualDesktopLayout & Qt::Horizontal) && (edge->isLeft() || edge->isRight())) { ++ edge->reserve(); ++ } ++ if ((m_virtualDesktopLayout & Qt::Vertical) & (edge->isTop() || edge->isBottom())) { ++ edge->reserve(); ++ } ++ } ++ } ++ return edge; ++} + +- if (pushback_pixels == 0) { +- // no pushback so we have to activate at once +- m_screenEdgeTimeLast = now; +- m_currentScreenEdge = border; +- m_screenEdgePushPoint = pos; +- } +- +- if ((m_currentScreenEdge == border) && +- (timestampDiff(m_screenEdgeTimeLast, now) < treshold_reset) && +- (timestampDiff(m_screenEdgeTimeLastTrigger, now) > treshold_trigger) && +- ((pos - m_screenEdgePushPoint).manhattanLength() < distance_reset)) { +- m_screenEdgeTimeLast = now; +- +- if (timestampDiff(m_screenEdgeTimeFirst, now) > treshold_set) { +- m_currentScreenEdge = ElectricNone; +- m_screenEdgeTimeLastTrigger = now; +- if (Workspace::self()->getMovingClient()) { +- // If moving a client or have force doing the desktop switch +- if (options->electricBorders() != Options::ElectricDisabled) +- switchDesktop(border, pos); +- return; // Don't reset cursor position +- } else { +- if (options->electricBorders() == Options::ElectricAlways && +- (border == ElectricTop || border == ElectricRight || +- border == ElectricBottom || border == ElectricLeft)) { +- // If desktop switching is always enabled don't apply it to the corners if +- // an effect is applied to it (We will check that later). +- switchDesktop(border, pos); +- return; // Don't reset cursor position +- } +- switch(options->electricBorderAction(border)) { +- case ElectricActionDashboard: { // Display Plasma dashboard +- QDBusInterface plasmaApp("org.kde.plasma-desktop", "/App"); +- plasmaApp.call("toggleDashboard"); +- } +- break; +- case ElectricActionShowDesktop: { +- Workspace::self()->setShowingDesktop(!Workspace::self()->showingDesktop()); +- break; +- } +- case ElectricActionLockScreen: { // Lock the screen +- QDBusInterface screenSaver("org.kde.screensaver", "/ScreenSaver"); +- screenSaver.call("Lock"); +- } +- break; +- case ElectricActionPreventScreenLocking: { +- break; +- } +- case ElectricActionNone: // Either desktop switching or an effect +- default: { +- if (effects && static_cast(effects)->borderActivated(border)) +- {} // Handled by effects +- else { +- if (options->electricBorders() == Options::ElectricAlways) { +- switchDesktop(border, pos); +- return; // Don't reset cursor position +- } +- emit activated(border); +- } +- } +- } ++ElectricBorderAction ScreenEdge::actionForEdge(Edge* edge) const ++{ ++ switch (edge->border()) { ++ case ElectricTopLeft: ++ return m_actionTopLeft; ++ case ElectricTop: ++ return m_actionTop; ++ case ElectricTopRight: ++ return m_actionTopRight; ++ case ElectricRight: ++ return m_actionRight; ++ case ElectricBottomRight: ++ return m_actionBottomRight; ++ case ElectricBottom: ++ return m_actionBottom; ++ case ElectricBottomLeft: ++ return m_actionBottomLeft; ++ case ElectricLeft: ++ return m_actionLeft; ++ default: ++ // fall through ++ break; ++ } ++ return ElectricActionNone; ++} ++ ++void ScreenEdge::reserveDesktopSwitching(bool isToReserve, Qt::Orientations o) ++{ ++ if (!o) ++ return; ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ WindowBasedEdge *edge = *it; ++ if (edge->isCorner()) { ++ isToReserve ? edge->reserve() : edge->unreserve(); ++ } else { ++ if ((m_virtualDesktopLayout & Qt::Horizontal) && (edge->isLeft() || edge->isRight())) { ++ isToReserve ? edge->reserve() : edge->unreserve(); ++ } ++ if ((m_virtualDesktopLayout & Qt::Vertical) && (edge->isTop() || edge->isBottom())) { ++ isToReserve ? edge->reserve() : edge->unreserve(); + } + } +- } else { +- m_currentScreenEdge = border; +- m_screenEdgeTimeFirst = now; +- m_screenEdgeTimeLast = now; +- m_screenEdgePushPoint = pos; +- } +- +- // Reset the pointer to find out whether the user is really pushing +- // (the direction back from which it came, starting from top clockwise) +- const int xdiff[ELECTRIC_COUNT] = { 0, +- -pushback_pixels, +- -pushback_pixels, +- -pushback_pixels, +- 0, +- pushback_pixels, +- pushback_pixels, +- pushback_pixels +- }; +- const int ydiff[ELECTRIC_COUNT] = { pushback_pixels, +- pushback_pixels, +- 0, +- -pushback_pixels, +- -pushback_pixels, +- -pushback_pixels, +- 0, +- pushback_pixels +- }; +- QCursor::setPos(pos.x() + xdiff[border], pos.y() + ydiff[border]); +-} +- +-void ScreenEdge::switchDesktop(ElectricBorder border, const QPoint& _pos) +-{ +- QPoint pos = _pos; +- int desk = Workspace::self()->currentDesktop(); +- const int OFFSET = 2; +- if (border == ElectricLeft || border == ElectricTopLeft || border == ElectricBottomLeft) { +- desk = Workspace::self()->desktopToLeft(desk, options->isRollOverDesktops()); +- pos.setX(displayWidth() - 1 - OFFSET); +- } +- if (border == ElectricRight || border == ElectricTopRight || border == ElectricBottomRight) { +- desk = Workspace::self()->desktopToRight(desk, options->isRollOverDesktops()); +- pos.setX(OFFSET); +- } +- if (border == ElectricTop || border == ElectricTopLeft || border == ElectricTopRight) { +- desk = Workspace::self()->desktopAbove(desk, options->isRollOverDesktops()); +- pos.setY(displayHeight() - 1 - OFFSET); +- } +- if (border == ElectricBottom || border == ElectricBottomLeft || border == ElectricBottomRight) { +- desk = Workspace::self()->desktopBelow(desk, options->isRollOverDesktops()); +- pos.setY(OFFSET); +- } +- Client *c = Workspace::self()->getMovingClient(); +- if (c && c->rules()->checkDesktop(desk) != desk) +- return; // user attempts to move a client to another desktop where it is ruleforced to not be +- int desk_before = Workspace::self()->currentDesktop(); +- Workspace::self()->setCurrentDesktop(desk); +- if (Workspace::self()->currentDesktop() != desk_before) +- QCursor::setPos(pos); ++ } ++} ++ ++void ScreenEdge::reserve(ElectricBorder border, QObject* object, const char* slot) ++{ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ if ((*it)->border() == border) { ++ (*it)->reserve(object, slot); ++ } ++ } ++} ++ ++void ScreenEdge::unreserve(ElectricBorder border, QObject* object) ++{ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ if ((*it)->border() == border) { ++ (*it)->unreserve(object); ++ } ++ } ++} ++ ++void ScreenEdge::check(const QPoint& pos, const QDateTime &now, bool forceNoPushback) ++{ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ (*it)->check(pos, now, forceNoPushback); ++ } + } + + bool ScreenEdge::isEntered(XEvent* e) + { + if (e->type == EnterNotify) { +- for (int i = 0; i < ELECTRIC_COUNT; ++i) +- if (m_screenEdgeWindows[i] != None && e->xcrossing.window == m_screenEdgeWindows[i]) { +- // The user entered an electric border +- check(QPoint(e->xcrossing.x_root, e->xcrossing.y_root), e->xcrossing.time); +- return true; +- } ++ return handleEnterNotify(e->xcrossing.window, ++ QPoint(e->xcrossing.x_root, e->xcrossing.y_root), ++ QDateTime::fromMSecsSinceEpoch(e->xcrossing.time)); + } + if (e->type == ClientMessage) { + if (e->xclient.message_type == atoms->xdnd_position) { +- for (int i = 0; i < ELECTRIC_COUNT; ++i) +- if (m_screenEdgeWindows[i] != None && e->xclient.window == m_screenEdgeWindows[i]) { +- updateXTime(); +- check(QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff), xTime(), true); +- return true; +- } ++ return handleDndNotify(e->xclient.window, ++ QPoint(e->xclient.data.l[2] >> 16, e->xclient.data.l[2] & 0xffff)); ++ } ++ } ++ return false; ++} ++ ++bool ScreenEdge::handleEnterNotify(Window window, const QPoint &point, const QDateTime ×tamp) ++{ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ WindowBasedEdge *edge = *it; ++ if (!edge->isReserved()) { ++ continue; ++ } ++ if (edge->window() == window) { ++ edge->check(point, timestamp); ++ return true; ++ } ++ } ++ return false; ++} ++ ++bool ScreenEdge::handleDndNotify(Window window, const QPoint& point) ++{ ++ for (QList::iterator it = m_edges.begin(); it != m_edges.end(); ++it) { ++ WindowBasedEdge *edge = *it; ++ if (edge->isReserved() && edge->window() == window) { ++ updateXTime(); ++ edge->check(point, QDateTime::fromMSecsSinceEpoch(xTime()), true); ++ return true; + } + } + return false; +@@ -386,9 +893,14 @@ void ScreenEdge::ensureOnTop() + { + Window* windows = new Window[ 8 ]; // There are up to 8 borders + int pos = 0; +- for (int i = 0; i < ELECTRIC_COUNT; ++i) +- if (m_screenEdgeWindows[ i ] != None) +- windows[ pos++ ] = m_screenEdgeWindows[ i ]; ++ for (QList::const_iterator it = m_edges.constBegin(); ++ it != m_edges.constEnd(); ++ ++it) { ++ WindowBasedEdge *edge = *it; ++ if (edge->window() == None) { ++ windows[pos++] = edge->window(); ++ } ++ } + if (!pos) { + delete [] windows; + return; // No borders at all +@@ -399,9 +911,19 @@ void ScreenEdge::ensureOnTop() + } + + +-const QVector< Window >& ScreenEdge::windows() ++QVector ScreenEdge::windows() const + { +- return m_screenEdgeWindows; ++ QVector wins; ++ for (QList::const_iterator it = m_edges.constBegin(); ++ it != m_edges.constEnd(); ++ ++it) { ++ Window win =(*it)->window(); ++ if (win != None) { ++ wins.append(win); ++ } ++ } ++ return wins; + } ++ + } //namespace + +diff --git a/kwin/screenedge.h b/kwin/screenedge.h +index d7da6e9..83669ce 100644 +--- a/kwin/screenedge.h ++++ b/kwin/screenedge.h +@@ -30,11 +30,93 @@ along with this program. If not, see . + #define KWIN_SCREENEDGE_H + #include + #include +-#include "kwinglobals.h" ++#include ++#include ++ ++#include + ++#include "kwinglobals.h" + + namespace KWin { + ++class ScreenEdge; ++ ++class Edge: public QObject ++{ ++ Q_OBJECT ++public: ++ explicit Edge(ScreenEdge *edges); ++ virtual ~Edge(); ++ bool isLeft() const; ++ bool isRight() const; ++ bool isTop() const; ++ bool isBottom() const; ++ bool isCorner() const; ++ bool isScreenEdge(); ++ bool triggersFor(const QPoint &cursorPos) const; ++ void check(const QPoint &cursorPos, const QDateTime &triggerTime, bool forceNoPushBack = false); ++ bool isReserved() const; ++ ++ ElectricBorder border() const; ++ void reserve(QObject *object, const char *slot); ++ const QHash &callBacks() const; ++ ++public Q_SLOTS: ++ void reserve(); ++ void unreserve(); ++ void unreserve(QObject *object); ++ void setBorder(ElectricBorder border); ++ void setAction(ElectricBorderAction action); ++ void setGeometry(const QRect &geometry); ++ void checkBlocking(); ++protected: ++ ScreenEdge *edges(); ++ const ScreenEdge *edges() const; ++ const QRect &geometry() const; ++ bool isBlocked() const; ++ virtual void doGeometryUpdate(); ++ virtual void activate(); ++ virtual void deactivate(); ++ virtual void doUpdateBlocking(); ++private: ++ bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime); ++ void handle(const QPoint &cursorPos); ++ bool handleAction(); ++ bool handleByCallback(); ++ void switchDesktop(const QPoint &cursorPos); ++ void pushCursorBack(const QPoint &cursorPos); ++ ScreenEdge *m_edges; ++ ElectricBorder m_border; ++ ElectricBorderAction m_action; ++ int m_reserved; ++ QRect m_geometry; ++ QDateTime m_lastTrigger; ++ QDateTime m_lastReset; ++ QPoint m_triggeredPoint; ++ QHash m_callBacks; ++ bool m_blocked; ++}; ++ ++class WindowBasedEdge : public Edge ++{ ++ Q_OBJECT ++public: ++ explicit WindowBasedEdge(ScreenEdge *parent); ++ virtual ~WindowBasedEdge(); ++ ++ Window window() const; ++ ++protected: ++ virtual void doGeometryUpdate(); ++ virtual void doUpdateBlocking(); ++ virtual void activate(); ++ virtual void deactivate(); ++ ++private: ++ void createWindow(); ++ Window m_window; ++}; ++ + /** + * @short This class is used to handle the screen edges + * Screen Edge Window management. Screen Edges allow a user to change the virtual +@@ -50,6 +132,10 @@ public: + ScreenEdge(); + ~ScreenEdge(); + /** ++ * @internal ++ */ ++ void setConfig(KSharedConfig::Ptr config); ++ /** + * Initialize the screen edges. + */ + void init(); +@@ -60,27 +146,33 @@ public: + * @param now the time when the function is called + * @param forceNoPushBack needs to be called to workaround some DnD clients, don't use unless you want to chek on a DnD event + */ +- void check(const QPoint& pos, Time now, bool forceNoPushBack = false); ++ void check(const QPoint& pos, const QDateTime &now, bool forceNoPushBack = false); + /** +- * Restore the size of the specified screen edges +- * @param border the screen edge to restore the size of ++ * The (dpi dependent) length, reserved for the active corners of each edge - 1/3" + */ +- void restoreSize(ElectricBorder border); +- /** +- * Mark the specified screen edge as reserved in m_screenEdgeReserved ++ int cornerOffset() const; ++ /** ++ * Mark the specified screen edge as reserved. This method is provided for external activation ++ * like effects and scripts. When the effect/script does no longer need the edge it is supposed ++ * to call @link unreserve. + * @param border the screen edge to mark as reserved ++ * @param object The object on which the @p callback needs to be invoked ++ * @param callback The method name to be invoked - uses QMetaObject::invokeMethod ++ * @see unreserve ++ * @todo: add pointer to script/effect + */ +- void reserve(ElectricBorder border); ++ void reserve(ElectricBorder border, QObject *object, const char *slot); + /** +- * Mark the specified screen edge as unreserved in m_screenEdgeReserved ++ * Mark the specified screen edge as unreserved. This method is provided for external activation ++ * like effects and scripts. This method is only allowed to be called if @link reserve had been ++ * called before for the same @p border. An unbalanced calling of reserve/unreserve leads to the ++ * edge never being active or never being able to deactivate again. + * @param border the screen edge to mark as unreserved ++ * @param object the object on which the callback had been invoked ++ * @see reserve ++ * @todo: add pointer to script/effect + */ +- void unreserve(ElectricBorder border); +- /** +- * Reserve actions for screen edges, if reserve is true. Unreserve otherwise. +- * @param reserve indicated weather actions should be reserved or unreseved +- */ +- void reserveActions(bool isToReserve); ++ void unreserve(ElectricBorder border, QObject *object); + /** + * Reserve desktop switching for screen edges, if reserve is true. Unreserve otherwise. + * @param reserve indicated weather desktop switching should be reserved or unreseved +@@ -97,18 +189,45 @@ public: + * @param e the X event which is passed to this method. + */ + bool isEntered(XEvent * e); ++ + /** + * Returns a QVector of all existing screen edge windows + * @return all existing screen edge windows in a QVector + */ +- const QVector< Window >& windows(); +-public Q_SLOTS: ++ QVector< Window > windows() const; ++ ++ bool isDesktopSwitching() const; ++ bool isDesktopSwitchingMovingClients() const; ++ const QSize &cursorPushBackDistance() const; + /** +- * Update the screen edge windows. Add new ones if the user specified +- * a new action or enabled desktop switching. Remove, if user deleted +- * actions or disabled desktop switching. ++ * Minimum time between the push back of the cursor and the activation by re-entering the edge. + */ +- void update(bool force=false); ++ int timeThreshold() const; ++ /** ++ * Minimum time between triggers ++ **/ ++ int reActivationThreshold() const; ++ ElectricBorderAction actionTopLeft() const; ++ ElectricBorderAction actionTop() const; ++ ElectricBorderAction actionTopRight() const; ++ ElectricBorderAction actionRight() const; ++ ElectricBorderAction actionBottomRight() const; ++ ElectricBorderAction actionBottom() const; ++ ElectricBorderAction actionBottomLeft() const; ++ ElectricBorderAction actionLeft() const; ++ ++public Q_SLOTS: ++ void reconfigure(); ++ /** ++ * Updates the layout of virtual desktops and adjust the reserved borders in case of ++ * virtual desktop switching on edges. ++ **/ ++ void updateLayout(); ++ /** ++ * Recreates all edges e.g. after the screen size changes. ++ **/ ++ void recreateEdges(); ++ + Q_SIGNALS: + /** + * Emitted when the @p border got activated and there is neither an effect nor a global +@@ -116,24 +235,226 @@ Q_SIGNALS: + * @param border The border which got activated + **/ + void activated(ElectricBorder border); ++ ++ void checkBlocking(); ++ + private: +- /** +- * Switch the desktop if desktop switching is enabled and a screen edge +- * is entered to trigger this action. +- */ +- void switchDesktop(ElectricBorder border, const QPoint& pos); +- +- QVector< Window > m_screenEdgeWindows; +- QVector< int > m_screenEdgeReserved; // Corners/edges used by something +- ElectricBorder m_currentScreenEdge; +- int m_screenEdgeLeft; +- int m_screenEdgeRight; +- int m_screenEdgeTop; +- int m_screenEdgeBottom; +- Time m_screenEdgeTimeFirst; +- Time m_screenEdgeTimeLast; +- Time m_screenEdgeTimeLastTrigger; +- QPoint m_screenEdgePushPoint; ++ enum { ElectricDisabled = 0, ElectricMoveOnly = 1, ElectricAlways = 2 }; ++ void setDesktopSwitching(bool enable); ++ void setDesktopSwitchingMovingClients(bool enable); ++ void setCursorPushBackDistance(const QSize &distance); ++ void setTimeThreshold(int treshold); ++ void setReActivationThreshold(int reshold); ++ void createHorizontalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea); ++ void createVerticalEdge(ElectricBorder border, const QRect &screen, const QRect &fullArea); ++ WindowBasedEdge *createEdge(ElectricBorder border, int x, int y, int width, int height); ++ void setActionForBorder(ElectricBorder border, ElectricBorderAction *oldValue, ElectricBorderAction newValue); ++ ElectricBorderAction actionForEdge(Edge *edge) const; ++ bool handleEnterNotify(Window window, const QPoint &point, const QDateTime ×tamp); ++ bool handleDndNotify(Window window, const QPoint &point); ++ bool m_desktopSwitching; ++ bool m_desktopSwitchingMovingClients; ++ QSize m_cursorPushBackDistance; ++ int m_timeThreshold; ++ int m_reactivateThreshold; ++ Qt::Orientations m_virtualDesktopLayout; ++ QList m_edges; ++ KSharedConfig::Ptr m_config; ++ ElectricBorderAction m_actionTopLeft; ++ ElectricBorderAction m_actionTop; ++ ElectricBorderAction m_actionTopRight; ++ ElectricBorderAction m_actionRight; ++ ElectricBorderAction m_actionBottomRight; ++ ElectricBorderAction m_actionBottom; ++ ElectricBorderAction m_actionBottomLeft; ++ ElectricBorderAction m_actionLeft; ++ int m_cornerOffset; + }; ++ ++ ++ ++/********************************************************** ++ * Inlines Edge ++ *********************************************************/ ++ ++inline bool Edge::isBottom() const ++{ ++ return m_border == ElectricBottom || m_border == ElectricBottomLeft || m_border == ElectricBottomRight; ++} ++ ++inline bool Edge::isLeft() const ++{ ++ return m_border == ElectricLeft || m_border == ElectricTopLeft || m_border == ElectricBottomLeft; ++} ++ ++inline bool Edge::isRight() const ++{ ++ return m_border == ElectricRight || m_border == ElectricTopRight || m_border == ElectricBottomRight; ++} ++ ++inline bool Edge::isTop() const ++{ ++ return m_border == ElectricTop || m_border == ElectricTopLeft || m_border == ElectricTopRight; ++} ++ ++inline bool Edge::isCorner() const ++{ ++ return m_border == ElectricTopLeft ++ || m_border == ElectricTopRight ++ || m_border == ElectricBottomRight ++ || m_border == ElectricBottomLeft; ++} ++ ++inline bool Edge::isScreenEdge() ++{ ++ return m_border == ElectricLeft ++ || m_border == ElectricTop ++ || m_border == ElectricRight ++ || m_border == ElectricBottom; + } ++ ++inline bool Edge::isReserved() const ++{ ++ return m_reserved != 0; ++} ++ ++inline void Edge::setAction(ElectricBorderAction action) ++{ ++ m_action = action; ++} ++ ++inline void Edge::setBorder(ElectricBorder border) ++{ ++ m_border = border; ++} ++ ++inline ScreenEdge *Edge::edges() ++{ ++ return m_edges; ++} ++ ++inline const ScreenEdge *Edge::edges() const ++{ ++ return m_edges; ++} ++ ++inline const QRect &Edge::geometry() const ++{ ++ return m_geometry; ++} ++ ++inline ElectricBorder Edge::border() const ++{ ++ return m_border; ++} ++ ++inline const QHash &Edge::callBacks() const ++{ ++ return m_callBacks; ++} ++ ++inline bool Edge::isBlocked() const ++{ ++ return m_blocked; ++} ++ ++ ++/********************************************************** ++ * Inlines WindowBasedEdge ++ *********************************************************/ ++ ++inline Window KWin::WindowBasedEdge::window() const ++{ ++ return m_window; ++} ++ ++ ++/********************************************************** ++ * Inlines ScreenEdges ++ *********************************************************/ ++ ++inline void ScreenEdge::setConfig(KSharedConfig::Ptr config) ++{ ++ m_config = config; ++} ++ ++inline int ScreenEdge::cornerOffset() const ++{ ++ return m_cornerOffset; ++} ++ ++inline const QSize &ScreenEdge::cursorPushBackDistance() const ++{ ++ return m_cursorPushBackDistance; ++} ++ ++inline bool ScreenEdge::isDesktopSwitching() const ++{ ++ return m_desktopSwitching; ++} ++ ++inline bool ScreenEdge::isDesktopSwitchingMovingClients() const ++{ ++ return m_desktopSwitchingMovingClients; ++} ++ ++inline int ScreenEdge::reActivationThreshold() const ++{ ++ return m_reactivateThreshold; ++} ++ ++inline int ScreenEdge::timeThreshold() const ++{ ++ return m_timeThreshold; ++} ++ ++inline void ScreenEdge::setCursorPushBackDistance(const QSize &distance) ++{ ++ m_cursorPushBackDistance = distance; ++} ++ ++inline void ScreenEdge::setDesktopSwitching(bool enable) ++{ ++ if (enable == m_desktopSwitching) { ++ return; ++ } ++ m_desktopSwitching = enable; ++ reserveDesktopSwitching(enable, m_virtualDesktopLayout); ++} ++ ++inline void ScreenEdge::setDesktopSwitchingMovingClients(bool enable) ++{ ++ m_desktopSwitchingMovingClients = enable; ++} ++ ++inline void ScreenEdge::setReActivationThreshold(int treshold) ++{ ++ m_reactivateThreshold = treshold; ++} ++ ++inline void ScreenEdge::setTimeThreshold(int treshold) ++{ ++ m_timeThreshold = treshold; ++} ++ ++#define ACTION( name) \ ++inline ElectricBorderAction ScreenEdge::name() const \ ++{ \ ++ return m_##name; \ ++} ++ ++ACTION(actionTopLeft) ++ACTION(actionTop) ++ACTION(actionTopRight) ++ACTION(actionRight) ++ACTION(actionBottomRight) ++ACTION(actionBottom) ++ACTION(actionBottomLeft) ++ACTION(actionLeft) ++ ++#undef ACTION ++ ++} // namespace ++ + #endif // KWIN_SCREENEDGE_H ++ +diff --git a/kwin/scripting/scriptedeffect.cpp b/kwin/scripting/scriptedeffect.cpp +index e9c0509..a651556 100644 +--- a/kwin/scripting/scriptedeffect.cpp ++++ b/kwin/scripting/scriptedeffect.cpp +@@ -269,20 +269,10 @@ ScriptedEffect::ScriptedEffect() + , m_scriptFile(QString()) + { + connect(m_engine, SIGNAL(signalHandlerException(QScriptValue)), SLOT(signalHandlerException(QScriptValue))); +-#ifdef KWIN_BUILD_SCREENEDGES +- connect(Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(slotBorderActivated(ElectricBorder))); +-#endif + } + + ScriptedEffect::~ScriptedEffect() + { +-#ifdef KWIN_BUILD_SCREENEDGES +- for (QHash >::const_iterator it = m_screenEdgeCallbacks.constBegin(); +- it != m_screenEdgeCallbacks.constEnd(); +- ++it) { +- KWin::Workspace::self()->screenEdge()->unreserve(static_cast(it.key())); +- } +-#endif + } + + bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript) +diff --git a/kwin/scripting/scripting.cpp b/kwin/scripting/scripting.cpp +index 16a696c..59f2b43 100644 +--- a/kwin/scripting/scripting.cpp ++++ b/kwin/scripting/scripting.cpp +@@ -215,20 +215,10 @@ KWin::AbstractScript::AbstractScript(int id, QString scriptName, QString pluginN + if (m_pluginName.isNull()) { + m_pluginName = scriptName; + } +-#ifdef KWIN_BUILD_SCREENEDGES +- connect(KWin::Workspace::self()->screenEdge(), SIGNAL(activated(ElectricBorder)), SLOT(borderActivated(ElectricBorder))); +-#endif + } + + KWin::AbstractScript::~AbstractScript() + { +-#ifdef KWIN_BUILD_SCREENEDGES +- for (QHash >::const_iterator it = m_screenEdgeCallbacks.constBegin(); +- it != m_screenEdgeCallbacks.constEnd(); +- ++it) { +- KWin::Workspace::self()->screenEdge()->unreserve(static_cast(it.key())); +- } +-#endif + } + + KConfigGroup KWin::AbstractScript::config() const +diff --git a/kwin/scripting/scriptingutils.h b/kwin/scripting/scriptingutils.h +index 3ed7845..5d68ad7 100644 +--- a/kwin/scripting/scriptingutils.h ++++ b/kwin/scripting/scriptingutils.h +@@ -159,7 +159,7 @@ QScriptValue registerScreenEdge(QScriptContext *context, QScriptEngine *engine) + if (it == script->screenEdgeCallbacks().end()) { + // not yet registered + #ifdef KWIN_BUILD_SCREENEDGES +- KWin::Workspace::self()->screenEdge()->reserve(static_cast(edge)); ++ KWin::Workspace::self()->screenEdge()->reserve(static_cast(edge), script, "borderActivated"); + #endif + script->screenEdgeCallbacks().insert(edge, QList() << context->argument(1)); + } else { +diff --git a/kwin/workspace.cpp b/kwin/workspace.cpp +index dccc41f..343eed3 100644 +--- a/kwin/workspace.cpp ++++ b/kwin/workspace.cpp +@@ -270,7 +270,9 @@ void Workspace::screenChangeTimeout() + void Workspace::init() + { + #ifdef KWIN_BUILD_SCREENEDGES ++ m_screenEdge.setConfig(KGlobal::config()); + m_screenEdge.init(); ++ connect(options, SIGNAL(configChanged()), &m_screenEdge, SLOT(reconfigure())); + #endif + + // Not used yet +@@ -1008,12 +1010,6 @@ void Workspace::slotReconfigure() + kDebug(1212) << "Workspace::slotReconfigure()"; + reconfigureTimer.stop(); + +-#ifdef KWIN_BUILD_SCREENEDGES +- m_screenEdge.reserveActions(false); +- if (options->electricBorders() == Options::ElectricAlways) +- m_screenEdge.reserveDesktopSwitching(false, m_screenEdgeOrientation); +-#endif +- + bool borderlessMaximizedWindows = options->borderlessMaximizedWindows(); + + KGlobal::config()->reparseConfiguration(); +@@ -1046,19 +1042,6 @@ void Workspace::slotReconfigure() + c->triggerDecorationRepaint(); + } + +-#ifdef KWIN_BUILD_SCREENEDGES +- m_screenEdge.reserveActions(true); +- if (options->electricBorders() == Options::ElectricAlways) { +- QSize desktopMatrix = rootInfo->desktopLayoutColumnsRows(); +- m_screenEdgeOrientation = 0; +- if (desktopMatrix.width() > 1) +- m_screenEdgeOrientation |= Qt::Horizontal; +- if (desktopMatrix.height() > 1) +- m_screenEdgeOrientation |= Qt::Vertical; +- m_screenEdge.reserveDesktopSwitching(true, m_screenEdgeOrientation); +- } +- m_screenEdge.update(); +-#endif + loadWindowRules(); + for (ClientList::Iterator it = clients.begin(); + it != clients.end(); diff --git a/SPECS/kde-workspace.spec b/SPECS/kde-workspace.spec index 979065a..18b4947 100644 --- a/SPECS/kde-workspace.spec +++ b/SPECS/kde-workspace.spec @@ -10,7 +10,7 @@ Summary: KDE Workspace Name: kde-workspace Version: 4.10.5 -Release: 18%{?dist} +Release: 21%{?dist} License: GPLv2 URL: https://projects.kde.org/projects/kde/kde-workspace %global revision %(echo %{version} | cut -d. -f3) @@ -81,6 +81,12 @@ Patch27: kde-workspace-4.10.2-kdm-logind-multiseat.patch Patch28: kde-workspace-4.10.5-ksysguardd-setgroups.patch Patch29: kde-workspace-4.10.5-initgroups.patch +# hide generalWidget, jovie is disable +Patch30: kde-workspace-4.10.5-bz#1060058.patch + +# apps fail in KDE with unknown color name BACKGROUND +Patch31: kde-workspace-4.10.5-bz#1043686-cpp.patch + ## upstreamable patches: # "keyboard stops working", https://bugs.kde.org/show_bug.cgi?id=171685#c135 Patch50: kde-workspace-4.7.80-kde#171685.patch @@ -127,6 +133,10 @@ Patch103: kde-workspace-4.10.5-CVE-2013-4133.patch Patch104: kde-workspace-4.10.x-bz#1001708.patch Patch105: kde-workspace-4.10.x-bz#1001727.patch Patch106: kde-workspace-4.10.5-rhbz990146.patch +Patch107: kde-workspace-4.10.5-solid-bz#1109987.patch +Patch108: kde-workspace-4.11-bz#1040678.patch +Patch109: kde-workspace-4.11-bz#1090492.patch +Patch110: kde-workspace-4.11-bz#1109936.patch ## plasma active patches @@ -466,6 +476,8 @@ Requires: akonadi %patch27 -p1 -b .kdm_logind %patch28 -p1 -b .ksysguardd-setgroups %patch29 -p1 -b .kdm_greet-initgroups +%patch30 -p1 -b .bz#1060058 +%patch31 -p1 -b .bz#1043686 # upstreamable patches %patch50 -p1 -b .kde#171685 @@ -487,6 +499,10 @@ Requires: akonadi %patch104 -p1 -b .bz#1001708 %patch105 -p1 -b .bz#1001727 %patch106 -p1 -b .bz#990146 +%patch107 -p1 -b .bz#1109987 +%patch108 -p1 -b .bz#1040678 +%patch109 -p1 -b .bz#1090492 +%patch110 -p1 -b .bz#1109936 # Fedora patches %if 0%{?fedora} && 0%{?rhel} > 6 @@ -1058,6 +1074,20 @@ fi %changelog +* Tue Sep 02 2014 Daniel Vrátil - 4.10.5-21 +- Resolves: bz#1090492 - changing calendar settings does not appear in plasmoid until month changed (fixed patch) +- Resolves: bz#1109936 - incorrect dispaly corner detection with multiple displays (fixed patch) + +* Wed Aug 20 2014 Than Ngo - 4.10.5-20 +- Resolves: bz#1040678 - cannot assign custom keyboard shortcut for Show Desktop Grid +- Resolves: bz#1090492 - changing calendar settings does not appear in plasmoid until month changed +- Resolves: bz#1109936 - incorrect dispaly corner detection with multiple displays + +* Mon Aug 18 2014 Than Ngo - 4.10.5-19 +- Resolves: bz#1109987 +- Resolves: bz#1060058 +- Resolves: bz#1043686 + * Mon Apr 28 2014 Than Ngo - 4.10.5-18 - Resolves: bz#1091087