Merge branch 'Plasma/5.10'

This commit is contained in:
Martin Flöser 2017-06-20 07:11:16 +02:00
commit 33ca5025e7
12 changed files with 181 additions and 33 deletions

View file

@ -43,6 +43,7 @@ integrationTest(NAME testGlobalShortcuts SRCS globalshortcuts_test.cpp)
integrationTest(NAME testWindowSelection SRCS window_selection_test.cpp)
integrationTest(NAME testPointerConstraints SRCS pointer_constraints_test.cpp)
integrationTest(NAME testKeyboardLayout SRCS keyboard_layout_test.cpp)
integrationTest(NAME testKeymapCreationFailure SRCS keymap_creation_failure_test.cpp)
if (XCB_ICCCM_FOUND)
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)

View file

@ -0,0 +1,102 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "kwin_wayland_test.h"
#include "keyboard_input.h"
#include "keyboard_layout.h"
#include "platform.h"
#include "shell_client.h"
#include "virtualdesktops.h"
#include "wayland_server.h"
#include "workspace.h"
#include <KConfigGroup>
#include <KGlobalAccel>
#include <linux/input.h>
using namespace KWin;
using namespace KWayland::Client;
static const QString s_socketName = QStringLiteral("wayland_test_kwin_keymap_creation_failure-0");
class KeymapCreationFailureTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void testPointerButton();
};
void KeymapCreationFailureTest::initTestCase()
{
// situation for for BUG 381210
// this will fail to create keymap
qputenv("XKB_DEFAULT_RULES", "no");
qputenv("XKB_DEFAULT_MODEL", "no");
qputenv("XKB_DEFAULT_LAYOUT", "no");
qputenv("XKB_DEFAULT_VARIANT", "no");
qputenv("XKB_DEFAULT_OPTIONS", "no");
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
kwinApp()->setKxkbConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig));
KConfigGroup layoutGroup = kwinApp()->kxkbConfig()->group("Layout");
layoutGroup.writeEntry("LayoutList", QStringLiteral("no"));
layoutGroup.writeEntry("Model", "no");
layoutGroup.writeEntry("Options", "no");
layoutGroup.sync();
kwinApp()->start();
QVERIFY(workspaceCreatedSpy.wait());
waylandServer()->initWorkspace();
}
void KeymapCreationFailureTest::init()
{
QVERIFY(Test::setupWaylandConnection());
}
void KeymapCreationFailureTest::cleanup()
{
Test::destroyWaylandConnection();
}
void KeymapCreationFailureTest::testPointerButton()
{
// test case for BUG 381210
// pressing a pointer button results in crash
// now create the crashing condition
// which is sending in a pointer event
kwinApp()->platform()->pointerButtonPressed(BTN_LEFT, 0);
kwinApp()->platform()->pointerButtonReleased(BTN_LEFT, 1);
}
WAYLANDTEST_MAIN(KeymapCreationFailureTest)
#include "keymap_creation_failure_test.moc"

View file

@ -30,6 +30,7 @@ AbstractClient::AbstractClient(QObject *parent)
, m_hiddenInternal(false)
, m_keepBelow(false)
, m_geometry()
, m_resize(false)
{
}
@ -103,4 +104,14 @@ void AbstractClient::setKeepBelow(bool keepBelow)
emit keepBelowChanged();
}
bool AbstractClient::isResize() const
{
return m_resize;
}
void AbstractClient::setResize(bool set)
{
m_resize = set;
}
}

View file

@ -47,6 +47,8 @@ public:
void setHiddenInternal(bool set);
void setGeometry(const QRect &rect);
void setKeepBelow(bool);
bool isResize() const;
void setResize(bool set);
virtual void showOnScreenEdge() = 0;
Q_SIGNALS:
@ -60,6 +62,7 @@ private:
bool m_hiddenInternal;
bool m_keepBelow;
QRect m_geometry;
bool m_resize;
};
}

View file

@ -35,9 +35,4 @@ void Client::showOnScreenEdge()
setHiddenInternal(false);
}
bool Client::isResize() const
{
return false;
}
}

View file

@ -34,8 +34,6 @@ class Client : public AbstractClient
public:
explicit Client(QObject *parent);
virtual ~Client();
bool isResize() const;
void showOnScreenEdge() override;
};

View file

@ -392,6 +392,27 @@ void TestScreenEdges::testCreatingInitialEdges()
QCOMPARE(e->activatesForTouchGesture(), false);
QCOMPARE(e->approachGeometry(), expectedGeometries.at(i*2+1));
}
// let's start a move of window.
Client client(workspace());
workspace()->setMovingClient(&client);
for (int i = 0; i < 8; ++i) {
auto e = edges.at(i);
QVERIFY(!e->isReserved());
QCOMPARE(e->activatesForPointer(), true);
QCOMPARE(e->activatesForTouchGesture(), false);
QCOMPARE(e->approachGeometry(), expectedGeometries.at(i*2+1));
}
// not for resize
client.setResize(true);
for (int i = 0; i < 8; ++i) {
auto e = edges.at(i);
QVERIFY(!e->isReserved());
QCOMPARE(e->activatesForPointer(), false);
QCOMPARE(e->activatesForTouchGesture(), false);
QCOMPARE(e->approachGeometry(), expectedGeometries.at(i*2+1));
}
workspace()->setMovingClient(nullptr);
}
void TestScreenEdges::testCallback()

View file

@ -48,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "kwinglutils.h"
#include <QDebug>
#include <QDesktopWidget>
#include <Plasma/Theme>
@ -599,6 +600,11 @@ bool EffectsHandlerImpl::grabKeyboard(Effect* effect)
bool ret = grabXKeyboard();
if (!ret)
return false;
// Workaround for Qt 5.9 regression introduced with 2b34aefcf02f09253473b096eb4faffd3e62b5f4
// we no longer get any events for the root window, one needs to call winId() on the desktop window
// TODO: change effects event handling to create the appropriate QKeyEvent without relying on Qt
// as it's done already in the Wayland case.
qApp->desktop()->winId();
}
keyboard_grab_effect = effect;
return true;

View file

@ -183,6 +183,12 @@ bool Edge::activatesForPointer() const
if (m_edges->isDesktopSwitching()) {
return true;
}
if (m_edges->isDesktopSwitchingMovingClients()) {
auto c = Workspace::self()->getMovingClient();
if (c && !c->isResize()) {
return true;
}
}
if (!m_callBacks.isEmpty()) {
return true;
}
@ -293,10 +299,7 @@ bool Edge::canActivate(const QPoint &cursorPos, const QDateTime &triggerTime)
void Edge::handle(const QPoint &cursorPos)
{
AbstractClient *movingClient = Workspace::self()->getMovingClient();
bool isResize = false;
if (Client *movingClientClient = qobject_cast<Client*>(movingClient))
isResize = movingClientClient->isResize();
if ((edges()->isDesktopSwitchingMovingClients() && movingClient && !isResize) ||
if ((edges()->isDesktopSwitchingMovingClients() && movingClient && !movingClient->isResize()) ||
(edges()->isDesktopSwitching() && isScreenEdge())) {
// always switch desktops in case:
// moving a Client and option for switch on client move is enabled

View file

@ -284,7 +284,7 @@ TabBoxClientList TabBoxHandlerImpl::stackingOrder() const
ToplevelList stacking = Workspace::self()->stackingOrder();
TabBoxClientList ret;
foreach (Toplevel *toplevel, stacking) {
if (Client *client = qobject_cast<Client*>(toplevel)) {
if (auto client = qobject_cast<AbstractClient*>(toplevel)) {
ret.append(client->tabBoxClient());
}
}
@ -331,7 +331,7 @@ void TabBoxHandlerImpl::shadeClient(TabBoxClient *c, bool b) const
QWeakPointer<TabBoxClient> TabBoxHandlerImpl::desktopClient() const
{
foreach (Toplevel *toplevel, Workspace::self()->stackingOrder()) {
Client *client = qobject_cast<Client*>(toplevel);
auto client = qobject_cast<AbstractClient*>(toplevel);
if (client && client->isDesktop() && client->isOnCurrentDesktop() && client->screen() == screens()->current()) {
return client->tabBoxClient();
}
@ -1319,7 +1319,7 @@ void TabBox::walkThroughDesktops(bool forward)
void TabBox::CDEWalkThroughWindows(bool forward)
{
Client* c = nullptr;
AbstractClient* c = nullptr;
// this function find the first suitable client for unreasonable focus
// policies - the topmost one, with some exceptions (can't be keepabove/below,
// otherwise it gets stuck on them)
@ -1327,7 +1327,7 @@ void TabBox::CDEWalkThroughWindows(bool forward)
for (int i = Workspace::self()->stackingOrder().size() - 1;
i >= 0 ;
--i) {
Client* it = qobject_cast<Client*>(Workspace::self()->stackingOrder().at(i));
auto it = qobject_cast<AbstractClient*>(Workspace::self()->stackingOrder().at(i));
if (it && it->isOnCurrentActivity() && it->isOnCurrentDesktop() && !it->isSpecialWindow()
&& it->isShown(false) && it->wantsTabFocus()
&& !it->keepAbove() && !it->keepBelow()) {
@ -1335,14 +1335,14 @@ void TabBox::CDEWalkThroughWindows(bool forward)
break;
}
}
Client* nc = c;
AbstractClient* nc = c;
bool options_traverse_all;
{
KConfigGroup group(kwinApp()->config(), "TabBox");
options_traverse_all = group.readEntry("TraverseAll", false);
}
Client* firstClient = nullptr;
AbstractClient* firstClient = nullptr;
do {
nc = forward ? nextClientStatic(nc) : previousClientStatic(nc);
if (!firstClient) {
@ -1641,34 +1641,36 @@ int TabBox::previousDesktopStatic(int iDesktop) const
auxiliary functions to travers all clients according to the static
order. Useful for the CDE-style Alt-tab feature.
*/
Client* TabBox::nextClientStatic(Client* c) const
AbstractClient* TabBox::nextClientStatic(AbstractClient* c) const
{
if (!c || Workspace::self()->clientList().isEmpty())
const auto &list = Workspace::self()->allClientList();
if (!c || list.isEmpty())
return 0;
int pos = Workspace::self()->clientList().indexOf(c);
int pos = list.indexOf(c);
if (pos == -1)
return Workspace::self()->clientList().first();
return list.first();
++pos;
if (pos == Workspace::self()->clientList().count())
return Workspace::self()->clientList().first();
return Workspace::self()->clientList()[ pos ];
if (pos == list.count())
return list.first();
return list.at(pos);
}
/*!
auxiliary functions to travers all clients according to the static
order. Useful for the CDE-style Alt-tab feature.
*/
Client* TabBox::previousClientStatic(Client* c) const
AbstractClient* TabBox::previousClientStatic(AbstractClient* c) const
{
if (!c || Workspace::self()->clientList().isEmpty())
const auto &list = Workspace::self()->allClientList();
if (!c || list.isEmpty())
return 0;
int pos = Workspace::self()->clientList().indexOf(c);
int pos = list.indexOf(c);
if (pos == -1)
return Workspace::self()->clientList().last();
return list.last();
if (pos == 0)
return Workspace::self()->clientList().last();
return list.last();
--pos;
return Workspace::self()->clientList()[ pos ];
return list.at(pos);
}
bool TabBox::establishTabBoxGrab()

View file

@ -176,8 +176,8 @@ public:
void initShortcuts();
Client* nextClientStatic(Client*) const;
Client* previousClientStatic(Client*) const;
AbstractClient* nextClientStatic(AbstractClient*) const;
AbstractClient* previousClientStatic(AbstractClient*) const;
int nextDesktopStatic(int iDesktop) const;
int previousDesktopStatic(int iDesktop) const;
void keyPress(int key);

View file

@ -354,13 +354,16 @@ QString Xkb::layoutName() const
QString Xkb::layoutName(xkb_layout_index_t layout) const
{
if (!m_keymap) {
return QString{};
}
return QString::fromLocal8Bit(xkb_keymap_layout_get_name(m_keymap, layout));
}
QMap<xkb_layout_index_t, QString> Xkb::layoutNames() const
{
QMap<xkb_layout_index_t, QString> layouts;
const auto size = xkb_keymap_num_layouts(m_keymap);
const auto size = m_keymap ? xkb_keymap_num_layouts(m_keymap) : 0u;
for (xkb_layout_index_t i = 0; i < size; i++) {
layouts.insert(i, layoutName(i));
}
@ -387,6 +390,9 @@ void Xkb::updateConsumedModifiers(uint32_t key)
Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const
{
if (!m_state) {
return Qt::NoModifier;
}
Qt::KeyboardModifiers mods = Qt::NoModifier;
if (xkb_state_mod_index_is_active(m_state, m_shiftModifier, XKB_STATE_MODS_EFFECTIVE) == 1) {
mods |= Qt::ShiftModifier;