<commit_before>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: <NAME> <<EMAIL>>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QDBusConnection>
#include "lipstickcompositorwindow.h"
#include "lipstickcompositor.h"
#include "windowmodel.h"

WindowModel::WindowModel()
: m_complete(false)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!c) {
        qWarning("WindowModel: Compositor must be created before WindowModel");
    } else {
        c->m_windowModels.append(this);
    }

    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject("/WindowModel", this, QDBusConnection::ExportAllSlots);
    dbus.registerService("org.nemomobile.lipstick");
}

WindowModel::~WindowModel()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (c) c->m_windowModels.removeAll(this);
}

int WindowModel::itemCount() const
{
    return m_items.count();
}

int WindowModel::windowId(int index) const
{
    if (index < 0 || index >= m_items.count())
        return 0;
    return m_items.at(index);
}

int WindowModel::rowCount(const QModelIndex &) const
{
    return m_items.count();
}

QVariant WindowModel::data(const QModelIndex &index, int role) const
{
    int idx = index.row();
    if (idx < 0 || idx >= m_items.count())
        return QVariant();

    LipstickCompositor *c = LipstickCompositor::instance();
    if (role == Qt::UserRole + 1) {
        return m_items.at(idx);
    } else if (role == Qt::UserRole + 2) {
        QWaylandSurface *s = c->surfaceForId(m_items.at(idx));
        return s?s->processId():0;
    } else if (role == Qt::UserRole + 3) {
        LipstickCompositorWindow *w = static_cast<LipstickCompositorWindow *>(c->windowForId(m_items.at(idx)));
        return w->title();
    } else {
        return QVariant();
    }
}

QHash<int, QByteArray> WindowModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[Qt::UserRole + 1] = "window";
    roles[Qt::UserRole + 2] = "processId";
    roles[Qt::UserRole + 3] = "title";
    return roles;
}

void WindowModel::classBegin()
{
}

void WindowModel::componentComplete()
{
    m_complete = true;
    refresh();
}

/*!
    Reimplement this method to provide custom filtering.
*/
bool WindowModel::approveWindow(LipstickCompositorWindow *window)
{
    return window->isInProcess() == false && 
        window->category() != QLatin1String("overlay");
}

void WindowModel::addItem(int id)
{
    if (!m_complete)
        return;

    LipstickCompositor *c = LipstickCompositor::instance();
    LipstickCompositorWindow *window = static_cast<LipstickCompositorWindow *>(c->windowForId(id));
    if (!approveWindow(window))
        return;

    beginInsertRows(QModelIndex(), m_items.count(), m_items.count());
    m_items.append(id);
    endInsertRows();
    emit itemAdded(m_items.count() - 1);
    emit itemCountChanged();
}

void WindowModel::remItem(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    beginRemoveRows(QModelIndex(), idx, idx);
    m_items.removeAt(idx);
    endRemoveRows();
    emit itemCountChanged();
}

void WindowModel::titleChanged(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    emit dataChanged(index(idx, 0), index(idx, 0));
}

void WindowModel::refresh()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    beginResetModel();

    m_items.clear();

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
         iter != c->m_mappedSurfaces.end(); ++iter) {

        if (approveWindow(iter.value()))
            m_items.append(iter.key());
    }

    endResetModel();
}

// used by mapplauncherd to bring a binary to the front
void WindowModel::launchProcess(const QString &binaryName)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
        iter != c->m_mappedSurfaces.end(); ++iter) {

        LipstickCompositorWindow *win = iter.value();
        if (!approveWindow(win))
            continue;

        QString pidFile = QString::fromLatin1("/proc/%1/cmdline").arg(win->processId());
        QFile f(pidFile);
        if (!f.open(QIODevice::ReadOnly)) {
            qWarning() << Q_FUNC_INFO << "Cannot open cmdline for " << pidFile;
            continue;
        }

        // cmdline contains a \0, so we use constData to truncate that away
        QByteArray proc = QByteArray(f.readAll().constData());

        if (proc != binaryName)
            continue;

        win->surface()->raiseRequested();
        break;
    }
}
<commit_msg>[windowmodel] Add support for multi-arg binaryName in launchProcess<commit_after>/***************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: <NAME> <<EMAIL>>
**
** This file is part of lipstick.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QDBusConnection>
#include "lipstickcompositorwindow.h"
#include "lipstickcompositor.h"
#include "windowmodel.h"

WindowModel::WindowModel()
: m_complete(false)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!c) {
        qWarning("WindowModel: Compositor must be created before WindowModel");
    } else {
        c->m_windowModels.append(this);
    }

    QDBusConnection dbus = QDBusConnection::sessionBus();
    dbus.registerObject("/WindowModel", this, QDBusConnection::ExportAllSlots);
    dbus.registerService("org.nemomobile.lipstick");
}

WindowModel::~WindowModel()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (c) c->m_windowModels.removeAll(this);
}

int WindowModel::itemCount() const
{
    return m_items.count();
}

int WindowModel::windowId(int index) const
{
    if (index < 0 || index >= m_items.count())
        return 0;
    return m_items.at(index);
}

int WindowModel::rowCount(const QModelIndex &) const
{
    return m_items.count();
}

QVariant WindowModel::data(const QModelIndex &index, int role) const
{
    int idx = index.row();
    if (idx < 0 || idx >= m_items.count())
        return QVariant();

    LipstickCompositor *c = LipstickCompositor::instance();
    if (role == Qt::UserRole + 1) {
        return m_items.at(idx);
    } else if (role == Qt::UserRole + 2) {
        QWaylandSurface *s = c->surfaceForId(m_items.at(idx));
        return s?s->processId():0;
    } else if (role == Qt::UserRole + 3) {
        LipstickCompositorWindow *w = static_cast<LipstickCompositorWindow *>(c->windowForId(m_items.at(idx)));
        return w->title();
    } else {
        return QVariant();
    }
}

QHash<int, QByteArray> WindowModel::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[Qt::UserRole + 1] = "window";
    roles[Qt::UserRole + 2] = "processId";
    roles[Qt::UserRole + 3] = "title";
    return roles;
}

void WindowModel::classBegin()
{
}

void WindowModel::componentComplete()
{
    m_complete = true;
    refresh();
}

/*!
    Reimplement this method to provide custom filtering.
*/
bool WindowModel::approveWindow(LipstickCompositorWindow *window)
{
    return window->isInProcess() == false && 
        window->category() != QLatin1String("overlay");
}

void WindowModel::addItem(int id)
{
    if (!m_complete)
        return;

    LipstickCompositor *c = LipstickCompositor::instance();
    LipstickCompositorWindow *window = static_cast<LipstickCompositorWindow *>(c->windowForId(id));
    if (!approveWindow(window))
        return;

    beginInsertRows(QModelIndex(), m_items.count(), m_items.count());
    m_items.append(id);
    endInsertRows();
    emit itemAdded(m_items.count() - 1);
    emit itemCountChanged();
}

void WindowModel::remItem(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    beginRemoveRows(QModelIndex(), idx, idx);
    m_items.removeAt(idx);
    endRemoveRows();
    emit itemCountChanged();
}

void WindowModel::titleChanged(int id)
{
    if (!m_complete)
        return;

    int idx = m_items.indexOf(id);
    if (idx == -1)
        return;

    emit dataChanged(index(idx, 0), index(idx, 0));
}

void WindowModel::refresh()
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    beginResetModel();

    m_items.clear();

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
         iter != c->m_mappedSurfaces.end(); ++iter) {

        if (approveWindow(iter.value()))
            m_items.append(iter.key());
    }

    endResetModel();
}

// used by mapplauncherd to bring a binary to the front
void WindowModel::launchProcess(const QString &binaryName)
{
    LipstickCompositor *c = LipstickCompositor::instance();
    if (!m_complete || !c)
        return;

    QStringList binaryParts = binaryName.split(QRegExp(QRegExp("\\s+")));

    for (QHash<int, LipstickCompositorWindow *>::ConstIterator iter = c->m_mappedSurfaces.begin();
        iter != c->m_mappedSurfaces.end(); ++iter) {

        LipstickCompositorWindow *win = iter.value();
        if (!approveWindow(win))
            continue;

        QString pidFile = QString::fromLatin1("/proc/%1/cmdline").arg(win->processId());
        QFile f(pidFile);
        if (!f.open(QIODevice::ReadOnly)) {
            qWarning() << Q_FUNC_INFO << "Cannot open cmdline for " << pidFile;
            continue;
        }

        // Command line arguments are split by '\0' in /proc/*/cmdline
        QStringList proc;
        QByteArray data = f.readAll();
        Q_FOREACH (const QByteArray &array, data.split('\0')) {
            QString part = QString::fromUtf8(array);
            if (part.size() > 0) {
                proc << part;
            }
        }

        // Cannot match, as the cmdline has less arguments than then binary part
        if (binaryParts.size() > proc.size()) {
            continue;
        }

        bool match = true;

        // All parts of binaryName must be contained in this order in the
        // process command line to match the given process
        for (int i=0; i<binaryParts.count(); i++) {
            if (proc[i] != binaryParts[i]) {
                match = false;
                break;
            }
        }

        if (match) {
            win->surface()->raiseRequested();
            break;
        }
    }
}

{'fraction_non_alphanumeric': 0.162116794769856, 'fraction_numerical': 0.004770739464617015, 'mean_word_length': 3.2333582647718773, 'pattern_counts': {'":': 0, '<': 42, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5371491', 'n_tokens_mistral': 3576, 'n_tokens_neox': 3469, 'n_words': 815}