diff --git a/main.cpp b/main.cpp index e6e892a73..e4362f9f3 100644 --- a/main.cpp +++ b/main.cpp @@ -1,474 +1,475 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 1999, 2000 Matthias Ettrich Copyright (C) 2003 Lubos Lunak 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 . *********************************************************************/ #include "main.h" #include // kwin #include "platform.h" #include "atoms.h" #include "composite.h" #include "cursor.h" #include "input.h" #include "logind.h" #include "options.h" #include "screens.h" #include "screenlockerwatcher.h" #include "sm.h" #include "workspace.h" #include "xcbutils.h" #include #include "tabbox/accessibility.h" // KDE #include #include #include #include #include // Qt #include #include #include #include #include #include #include // system #ifdef HAVE_UNISTD_H #include #endif // HAVE_UNISTD_H #ifdef HAVE_MALLOC_H #include #endif // HAVE_MALLOC_H // xcb #include #ifndef XCB_GE_GENERIC #define XCB_GE_GENERIC 35 #endif Q_DECLARE_METATYPE(KSharedConfigPtr) namespace KWin { Options* options; Atoms* atoms; int screen_number = -1; bool is_multihead = false; int Application::crashes = 0; bool Application::isX11MultiHead() { return is_multihead; } void Application::setX11MultiHead(bool multiHead) { is_multihead = multiHead; } void Application::setX11ScreenNumber(int screenNumber) { screen_number = screenNumber; } int Application::x11ScreenNumber() { return screen_number; } QAccessibleInterface* accessibilityFactory(const QString &key, QObject* object) { + Q_UNUSED(key); // qDebug() << Q_FUNC_INFO << key << object; if (object == kwinApp()) { qDebug() << "RETURN A11Y for APP"; } return new KWinAccessibleApplication(kwinApp()); } Application::Application(Application::OperationMode mode, int &argc, char **argv) : QApplication(argc, argv) , m_eventFilter(new XcbEventFilter()) , m_configLock(false) , m_config() , m_kxkbConfig() , m_inputConfig() , m_operationMode(mode) { qRegisterMetaType("Options::WindowOperation"); qRegisterMetaType(); qRegisterMetaType("KWayland::Server::SurfaceInterface *"); qRegisterMetaType(); // By default we would get a QAccessibleApplication created for our // main app. That doesn't do the trick for the purpose of faking the tab handler. QAccessible::installFactory(KWin::accessibilityFactory); } void Application::setConfigLock(bool lock) { m_configLock = lock; } Application::OperationMode Application::operationMode() const { return m_operationMode; } void Application::setOperationMode(OperationMode mode) { m_operationMode = mode; } bool Application::shouldUseWaylandForCompositing() const { return m_operationMode == OperationModeWaylandOnly || m_operationMode == OperationModeXwayland; } void Application::start() { setQuitOnLastWindowClosed(false); if (!m_config) { m_config = KSharedConfig::openConfig(); } if (!m_config->isImmutable() && m_configLock) { // TODO: This shouldn't be necessary //config->setReadOnly( true ); m_config->reparseConfiguration(); } if (!m_kxkbConfig) { m_kxkbConfig = KSharedConfig::openConfig(QStringLiteral("kxkbrc"), KConfig::NoGlobals); } if (!m_inputConfig) { m_inputConfig = KSharedConfig::openConfig(QStringLiteral("kcminputrc"), KConfig::NoGlobals); } performStartup(); } Application::~Application() { delete options; destroyAtoms(); } void Application::destroyAtoms() { delete atoms; atoms = nullptr; } void Application::resetCrashesCount() { crashes = 0; } void Application::setCrashCount(int count) { crashes = count; } bool Application::wasCrash() { return crashes > 0; } static const char description[] = I18N_NOOP("KDE window manager"); void Application::createAboutData() { KAboutData aboutData(QStringLiteral(KWIN_NAME), // The program name used internally i18n("KWin"), // A displayable program name string QStringLiteral(KWIN_VERSION_STRING), // The program version string i18n(description), // Short description of what the app does KAboutLicense::GPL, // The license this code is released under i18n("(c) 1999-2013, The KDE Developers")); // Copyright Statement aboutData.addAuthor(i18n("Matthias Ettrich"), QString(), QStringLiteral("ettrich@kde.org")); aboutData.addAuthor(i18n("Cristian Tibirna"), QString(), QStringLiteral("tibirna@kde.org")); aboutData.addAuthor(i18n("Daniel M. Duley"), QString(), QStringLiteral("mosfet@kde.org")); aboutData.addAuthor(i18n("Luboš Luňák"), QString(), QStringLiteral("l.lunak@kde.org")); aboutData.addAuthor(i18n("Martin Gräßlin"), i18n("Maintainer"), QStringLiteral("mgraesslin@kde.org")); KAboutData::setApplicationData(aboutData); } static const QString s_lockOption = QStringLiteral("lock"); static const QString s_crashesOption = QStringLiteral("crashes"); void Application::setupCommandLine(QCommandLineParser *parser) { QCommandLineOption lockOption(s_lockOption, i18n("Disable configuration options")); QCommandLineOption crashesOption(s_crashesOption, i18n("Indicate that KWin has recently crashed n times"), QStringLiteral("n")); parser->setApplicationDescription(i18n("KDE window manager")); parser->addVersionOption(); parser->addHelpOption(); parser->addOption(lockOption); parser->addOption(crashesOption); KAboutData::applicationData().setupCommandLine(parser); } void Application::processCommandLine(QCommandLineParser *parser) { setConfigLock(parser->isSet(s_lockOption)); Application::setCrashCount(parser->value(s_crashesOption).toInt()); } void Application::setupTranslator() { QTranslator *qtTranslator = new QTranslator(qApp); qtTranslator->load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); installTranslator(qtTranslator); } void Application::setupMalloc() { #ifdef M_TRIM_THRESHOLD // Prevent fragmentation of the heap by malloc (glibc). // // The default threshold is 128*1024, which can result in a large memory usage // due to fragmentation especially if we use the raster graphicssystem. On the // otherside if the threshold is too low, free() starts to permanently ask the kernel // about shrinking the heap. #ifdef HAVE_UNISTD_H const int pagesize = sysconf(_SC_PAGESIZE); #else const int pagesize = 4*1024; #endif // HAVE_UNISTD_H mallopt(M_TRIM_THRESHOLD, 5*pagesize); #endif // M_TRIM_THRESHOLD } void Application::setupLocalizedString() { KLocalizedString::setApplicationDomain("kwin"); } void Application::notifyKSplash() { // Tell KSplash that KWin has started QDBusMessage ksplashProgressMessage = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KSplash"), QStringLiteral("/KSplash"), QStringLiteral("org.kde.KSplash"), QStringLiteral("setStage")); ksplashProgressMessage.setArguments(QList() << QStringLiteral("wm")); QDBusConnection::sessionBus().asyncCall(ksplashProgressMessage); } void Application::createWorkspace() { // we want all QQuickWindows with an alpha buffer, do here as Workspace might create QQuickWindows QQuickWindow::setDefaultAlphaBuffer(true); // This tries to detect compositing options and can use GLX. GLX problems // (X errors) shouldn't cause kwin to abort, so this is out of the // critical startup section where x errors cause kwin to abort. // create workspace. (void) new Workspace(m_originalSessionKey); emit workspaceCreated(); } void Application::createInput() { ScreenLockerWatcher::create(this); LogindIntegration::create(this); auto input = InputRedirection::create(this); input->init(); m_platform->createPlatformCursor(this); } void Application::createScreens() { if (Screens::self()) { return; } Screens::create(this); emit screensCreated(); } void Application::createAtoms() { atoms = new Atoms; } void Application::createOptions() { options = new Options; } void Application::createCompositor() { Compositor::create(this); } void Application::setupEventFilters() { installNativeEventFilter(m_eventFilter.data()); } void Application::destroyWorkspace() { delete Workspace::self(); } void Application::destroyCompositor() { delete Compositor::self(); } void Application::updateX11Time(xcb_generic_event_t *event) { xcb_timestamp_t time = XCB_TIME_CURRENT_TIME; const uint8_t eventType = event->response_type & ~0x80; switch(eventType) { case XCB_KEY_PRESS: case XCB_KEY_RELEASE: time = reinterpret_cast(event)->time; break; case XCB_BUTTON_PRESS: case XCB_BUTTON_RELEASE: time = reinterpret_cast(event)->time; break; case XCB_MOTION_NOTIFY: time = reinterpret_cast(event)->time; break; case XCB_ENTER_NOTIFY: case XCB_LEAVE_NOTIFY: time = reinterpret_cast(event)->time; break; case XCB_FOCUS_IN: case XCB_FOCUS_OUT: case XCB_KEYMAP_NOTIFY: case XCB_EXPOSE: case XCB_GRAPHICS_EXPOSURE: case XCB_NO_EXPOSURE: case XCB_VISIBILITY_NOTIFY: case XCB_CREATE_NOTIFY: case XCB_DESTROY_NOTIFY: case XCB_UNMAP_NOTIFY: case XCB_MAP_NOTIFY: case XCB_MAP_REQUEST: case XCB_REPARENT_NOTIFY: case XCB_CONFIGURE_NOTIFY: case XCB_CONFIGURE_REQUEST: case XCB_GRAVITY_NOTIFY: case XCB_RESIZE_REQUEST: case XCB_CIRCULATE_NOTIFY: case XCB_CIRCULATE_REQUEST: // no timestamp return; case XCB_PROPERTY_NOTIFY: time = reinterpret_cast(event)->time; break; case XCB_SELECTION_CLEAR: time = reinterpret_cast(event)->time; break; case XCB_SELECTION_REQUEST: time = reinterpret_cast(event)->time; break; case XCB_SELECTION_NOTIFY: time = reinterpret_cast(event)->time; break; case XCB_COLORMAP_NOTIFY: case XCB_CLIENT_MESSAGE: case XCB_MAPPING_NOTIFY: case XCB_GE_GENERIC: // no timestamp return; default: // extension handling if (Xcb::Extensions::self()) { if (eventType == Xcb::Extensions::self()->shapeNotifyEvent()) { time = reinterpret_cast(event)->server_time; } if (eventType == Xcb::Extensions::self()->damageNotifyEvent()) { time = reinterpret_cast(event)->timestamp; } } break; } setX11Time(time); } bool XcbEventFilter::nativeEventFilter(const QByteArray &eventType, void *message, long int *result) { Q_UNUSED(result) if (eventType != "xcb_generic_event_t") { return false; } auto event = static_cast(message); kwinApp()->updateX11Time(event); if (!Workspace::self()) { // Workspace not yet created return false; } return Workspace::self()->workspaceEvent(event); } static bool s_useLibinput = false; void Application::setUseLibinput(bool use) { s_useLibinput = use; } bool Application::usesLibinput() { return s_useLibinput; } QProcessEnvironment Application::processStartupEnvironment() const { return QProcessEnvironment::systemEnvironment(); } void Application::initPlatform(const KPluginMetaData &plugin) { Q_ASSERT(!m_platform); m_platform = qobject_cast(plugin.instantiate()); if (m_platform) { m_platform->setParent(this); // check whether it needs libinput const QJsonObject &metaData = plugin.rawData(); auto it = metaData.find(QStringLiteral("input")); if (it != metaData.end()) { if ((*it).isBool()) { if (!(*it).toBool()) { qCDebug(KWIN_CORE) << "Platform does not support input, enforcing libinput support"; setUseLibinput(true); } } } } } } // namespace diff --git a/tabbox/accessibility.cpp b/tabbox/accessibility.cpp index bacc9c645..45f64368c 100644 --- a/tabbox/accessibility.cpp +++ b/tabbox/accessibility.cpp @@ -1,86 +1,160 @@ #include "tabbox/accessibility.h" +#include "tabbox/tabbox.h" #include "main.h" +#include "abstract_client.h" #include using namespace KWin; +// When doing anything, the window needs to be activated: +//QAccessible::State state; +//state.active = true; +//QAccessibleStateChangeEvent event(this, state); +//QAccessible::updateAccessibility(&event); + +// AND deactivated when hiding the tabbox + TabBoxAccessible::TabBoxAccessible(TabBox::TabBox *parent) : QAccessibleObject(parent) { auto *appInterface = QAccessible::queryAccessibleInterface(KWin::kwinApp()); KWinAccessibleApplication *appAccessible = static_cast(appInterface); appAccessible->addChildAccessible(this); qDebug() << Q_FUNC_INFO << "Created tab box accessible with object:" << parent; } QAccessibleInterface *TabBoxAccessible::parent() const { return QAccessible::queryAccessibleInterface(KWin::kwinApp()); } QAccessibleInterface *TabBoxAccessible::child(int index) const { - Q_UNUSED(index); // FIXME + if (!tabbox()) { + return nullptr; + } + + if (index >= 0 && index < tabbox()->currentClientList().size()) { + // FIXME: go through factory to get the cache used + return new ClientAccessible(tabbox()->currentClientList().at(index)); + } + return nullptr; } int TabBoxAccessible::childCount() const { + if (tabbox()) { +// if (tabbox()->isShown()) { + return tabbox()->currentClientList().size(); +// } + } return 0; } int TabBoxAccessible::indexOfChild(const QAccessibleInterface *) const { return -1; } QString TabBoxAccessible::text(QAccessible::Text t) const { + QString window; + if (tabbox() && tabbox()->currentClient()) { + window = tabbox()->currentClient()->caption(); + } + if (t == QAccessible::Name) { - return "Window Switcher Window"; + return QStringLiteral("Window Switcher: ") + window; + } else if (t == QAccessible::Description) { + + return QStringLiteral("KWIN THING description"); // FIXME } - return "KWIN THING"; // FIXME + return QString(); } QAccessible::Role TabBoxAccessible::role() const { return QAccessible::Window; } QAccessible::State TabBoxAccessible::state() const { QAccessible::State s; s.focused = true; return s; } +TabBox::TabBox *TabBoxAccessible::tabbox() const +{ + return static_cast(object()); +} + KWinAccessibleApplication::KWinAccessibleApplication(Application *app) { Q_UNUSED(app); // FIXME remove parameter? } int KWinAccessibleApplication::childCount() const { int count = QAccessibleApplication::childCount(); if (m_child) { ++count; } return count; } QAccessibleInterface *KWinAccessibleApplication::child(int index) const { // qDebug() << Q_FUNC_INFO << index << "CC" << QAccessibleApplication::childCount(); if (index < QAccessibleApplication::childCount()) { return QAccessibleApplication::child(index); } else if (index == QAccessibleApplication::childCount()) { qDebug() << "Getting VIRTUAL CHILD"; return m_child; } // qDebug() << "Returning nullptr as child"; return nullptr; } int KWinAccessibleApplication::indexOfChild(const QAccessibleInterface *child) const { if (child == m_child) { return childCount() - 1; } return QAccessibleApplication::indexOfChild(child); } + +ClientAccessible::ClientAccessible(AbstractClient *client) + : QAccessibleObject(client) +{ +} + +QAccessibleInterface *ClientAccessible::parent() const +{ + // FIXME + return nullptr; +} + +QString ClientAccessible::text(QAccessible::Text t) const +{ + auto *aClient = client(); + if (aClient) { + if (t == QAccessible::Name) { + return aClient->caption(); + } + } + return QString(); +} + +QAccessible::Role ClientAccessible::role() const +{ + return QAccessible::Button; // FIXME +} + +QAccessible::State ClientAccessible::state() const +{ + QAccessible::State s; // FIXME + return s; +} + +AbstractClient *ClientAccessible::client() const +{ + return static_cast(object()); +} diff --git a/tabbox/accessibility.h b/tabbox/accessibility.h index cc7ab3ecf..5eeed63c7 100644 --- a/tabbox/accessibility.h +++ b/tabbox/accessibility.h @@ -1,72 +1,84 @@ #include #include // ### FIXME #include "tabbox/tabbox.h" -// #include "main.h" #ifndef KWIN_TABBOX_ACCESSIBILITY_H #define KWIN_TABBOX_ACCESSIBILITY_H -// namespace and stuff (why?) namespace KWin { +class AbstractClient; + +class ClientAccessible : public QAccessibleObject +{ +public: + ClientAccessible(AbstractClient *client); + + QAccessibleInterface* parent() const override; + + QAccessibleInterface *child(int) const override + { return nullptr; } + int childCount() const override { return 0; } + int indexOfChild(const QAccessibleInterface *) const override + { return -1; } + + QString text(QAccessible::Text t) const override; + QAccessible::Role role() const override; + QAccessible::State state() const override; + +private: + AbstractClient *client() const; +}; class TabBoxAccessible : public QAccessibleObject { public: TabBoxAccessible(KWin::TabBox::TabBox *parent); QAccessibleInterface* parent() const override; -// bool isValid() const override; -// QObject *object() const override; -// QWindow *window() const; - - // relations -// QVector > relations(QAccessible::Relation match = QAccessible::AllRelations) const; // QAccessibleInterface *focusChild() const; -// QAccessibleInterface *childAt(int x, int y) const override; - - // navigation, hierarchy QAccessibleInterface *child(int index) const override; int childCount() const override; int indexOfChild(const QAccessibleInterface *) const override; - // properties and state QString text(QAccessible::Text) const override; -// QRect rect() const override; QAccessible::Role role() const override; QAccessible::State state() const override; + +private: + KWin::TabBox::TabBox *tabbox() const; }; class Application; class KWinAccessibleApplication : public QAccessibleApplication { public: KWinAccessibleApplication(Application *app); int childCount() const override; QAccessibleInterface *child(int index) const override; int indexOfChild(const QAccessibleInterface *child) const override; void addChildAccessible(QAccessibleInterface *child) { qDebug() << Q_FUNC_INFO << "child" << child; m_child = child; // FIXME: lifetime!!! } private: Application *m_KWinApplication = nullptr; QAccessibleInterface *m_child = nullptr; }; } #endif