diff options
Diffstat (limited to 'src/winextras/qwinjumplist.cpp')
-rw-r--r-- | src/winextras/qwinjumplist.cpp | 608 |
1 files changed, 0 insertions, 608 deletions
diff --git a/src/winextras/qwinjumplist.cpp b/src/winextras/qwinjumplist.cpp deleted file mode 100644 index f479096..0000000 --- a/src/winextras/qwinjumplist.cpp +++ /dev/null @@ -1,608 +0,0 @@ -/**************************************************************************** - ** - ** Copyright (C) 2016 Ivan Vizir <define-true-false@yandex.com> - ** Copyright (C) 2016 The Qt Company Ltd. - ** Contact: https://www.qt.io/licensing/ - ** - ** This file is part of the QtWinExtras module of the Qt Toolkit. - ** - ** $QT_BEGIN_LICENSE:LGPL$ - ** Commercial License Usage - ** Licensees holding valid commercial Qt licenses may use this file in - ** accordance with the commercial license agreement provided with the - ** Software or, alternatively, in accordance with the terms contained in - ** a written agreement between you and The Qt Company. For licensing terms - ** and conditions see https://www.qt.io/terms-conditions. For further - ** information use the contact form at https://www.qt.io/contact-us. - ** - ** GNU Lesser General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU Lesser - ** General Public License version 3 as published by the Free Software - ** Foundation and appearing in the file LICENSE.LGPL3 included in the - ** packaging of this file. Please review the following information to - ** ensure the GNU Lesser General Public License version 3 requirements - ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. - ** - ** GNU General Public License Usage - ** Alternatively, this file may be used under the terms of the GNU - ** General Public License version 2.0 or (at your option) the GNU General - ** Public license version 3 or any later version approved by the KDE Free - ** Qt Foundation. The licenses are as published by the Free Software - ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 - ** included in the packaging of this file. Please review the following - ** information to ensure the GNU General Public License requirements will - ** be met: https://www.gnu.org/licenses/gpl-2.0.html and - ** https://www.gnu.org/licenses/gpl-3.0.html. - ** - ** $QT_END_LICENSE$ - ** - ****************************************************************************/ - -#include <QtCore/qglobal.h> - -#ifdef Q_CC_MINGW // MinGW: Enable SHCreateItemFromParsingName() -# if defined(_WIN32_IE) && _WIN32_IE < 0x0700 // _WIN32_IE_IE70 -# undef _WIN32_IE -# endif -# ifndef _WIN32_IE -# define _WIN32_IE 0x0700 -# endif -#endif // Q_CC_MINGW - -#include "qwinjumplist.h" -#include "qwinjumplist_p.h" -#include "qwinjumplistitem.h" -#include "qwinjumplistcategory.h" -#include "qwinjumplistcategory_p.h" -#include "windowsguidsdefs_p.h" -#include "winpropkey_p.h" - -#include <QtCore/qdir.h> -#include <QtCore/qdebug.h> -#include <QtCore/qcoreapplication.h> -#include <QtCore/qregularexpression.h> -#include <QtCore/qt_windows.h> -#include <propvarutil.h> - -#include "qwinfunctions.h" -#include "qwinfunctions_p.h" -#include "winpropkey_p.h" - -#include <shobjidl.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QWinJumpList - \inmodule QtWinExtras - \brief The QWinJumpList class represents a transparent wrapper around Windows - Jump Lists. - - \since 5.2 - - An application can use Jump Lists to provide users with faster access to - files or to display shortcuts to tasks or commands. - */ - -/*! - \title Application User Model IDs - \externalpage http://msdn.microsoft.com/en-us/library/windows/desktop/dd378459%28v=vs.85%29.aspx - */ - -// partial copy of qprocess_win.cpp:qt_create_commandline() -static QString createArguments(const QStringList &arguments) -{ - QString args; - for (int i=0; i<arguments.size(); ++i) { - QString tmp = arguments.at(i); - // Quotes are escaped and their preceding backslashes are doubled. - tmp.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); - if (tmp.isEmpty() || tmp.contains(u' ') || tmp.contains(u'\t')) { - // The argument must not end with a \ since this would be interpreted - // as escaping the quote -- rather put the \ behind the quote: e.g. - // rather use "foo"\ than "foo\" - int i = tmp.length(); - while (i > 0 && tmp.at(i - 1) == u'\\') - --i; - tmp.insert(i, u'"'); - tmp.prepend(u'"'); - } - args += u' ' + tmp; - } - return args; -} - -void QWinJumpListPrivate::warning(const char *function, HRESULT hresult) -{ - const QString err = QtWin::errorStringFromHresult(hresult); - qWarning("QWinJumpList: %s() failed: %#010x, %s.", function, unsigned(hresult), qPrintable(err)); -} - -QString QWinJumpListPrivate::iconsDirPath() -{ - QString iconDirPath = QDir::tempPath() + u'/' - + QCoreApplication::applicationName() + QLatin1String("/qt-jl-icons/"); - QDir().mkpath(iconDirPath); - return iconDirPath; -} - -void QWinJumpListPrivate::invalidate() -{ - Q_Q(QWinJumpList); - if (!pDestList) - return; - - if (!dirty) { - dirty = true; - QMetaObject::invokeMethod(q, "_q_rebuild", Qt::QueuedConnection); - } -} - -void QWinJumpListPrivate::_q_rebuild() -{ - if (beginList()) { - if (recent && recent->isVisible()) - appendKnownCategory(KDC_RECENT); - if (frequent && frequent->isVisible()) - appendKnownCategory(KDC_FREQUENT); - for (QWinJumpListCategory *category : qAsConst(categories)) { - if (category->isVisible()) - appendCustomCategory(category); - } - if (tasks && tasks->isVisible()) - appendTasks(tasks->items()); - commitList(); - } - dirty = false; -} - -void QWinJumpListPrivate::destroy() -{ - delete recent; - recent = nullptr; - delete frequent; - frequent = nullptr; - delete tasks; - tasks = nullptr; - qDeleteAll(categories); - categories.clear(); - invalidate(); -} - -bool QWinJumpListPrivate::beginList() -{ - HRESULT hresult = S_OK; - if (!identifier.isEmpty()) { - wchar_t *id = qt_qstringToNullTerminated(identifier); - hresult = pDestList->SetAppID(id); - delete[] id; - } - if (SUCCEEDED(hresult)) { - UINT maxSlots = 0; - IUnknown *array = nullptr; - hresult = pDestList->BeginList(&maxSlots, qIID_IUnknown, reinterpret_cast<void **>(&array)); - if (array) - array->Release(); - } - if (FAILED(hresult)) - QWinJumpListPrivate::warning("BeginList", hresult); - return SUCCEEDED(hresult); -} - -bool QWinJumpListPrivate::commitList() -{ - HRESULT hresult = pDestList->CommitList(); - if (FAILED(hresult)) - QWinJumpListPrivate::warning("CommitList", hresult); - return SUCCEEDED(hresult); -} - -void QWinJumpListPrivate::appendKnownCategory(KNOWNDESTCATEGORY category) -{ - HRESULT hresult = pDestList->AppendKnownCategory(category); - if (FAILED(hresult)) - QWinJumpListPrivate::warning("AppendKnownCategory", hresult); -} - -void QWinJumpListPrivate::appendCustomCategory(QWinJumpListCategory *category) -{ - IObjectCollection *collection = toComCollection(category->items()); - if (collection) { - wchar_t *title = qt_qstringToNullTerminated(category->title()); - HRESULT hresult = pDestList->AppendCategory(title, collection); - if (FAILED(hresult)) - QWinJumpListPrivate::warning("AppendCategory", hresult); - delete[] title; - collection->Release(); - } -} - -void QWinJumpListPrivate::appendTasks(const QList<QWinJumpListItem *> &items) -{ - IObjectCollection *collection = toComCollection(items); - if (collection) { - HRESULT hresult = pDestList->AddUserTasks(collection); - if (FAILED(hresult)) - QWinJumpListPrivate::warning("AddUserTasks", hresult); - collection->Release(); - } -} - -QList<QWinJumpListItem *> QWinJumpListPrivate::fromComCollection(IObjectArray *array) -{ - QList<QWinJumpListItem *> list; - UINT count = 0; - array->GetCount(&count); - for (UINT i = 0; i < count; ++i) { - IUnknown *collectionItem = nullptr; - HRESULT hresult = array->GetAt(i, qIID_IUnknown, reinterpret_cast<void **>(&collectionItem)); - if (FAILED(hresult)) { - QWinJumpListPrivate::warning("GetAt", hresult); - continue; - } - IShellItem2 *shellItem = nullptr; - IShellLinkW *shellLink = nullptr; - QWinJumpListItem *jumplistItem = nullptr; - if (SUCCEEDED(collectionItem->QueryInterface(qIID_IShellItem2, reinterpret_cast<void **>(&shellItem)))) { - jumplistItem = fromIShellItem(shellItem); - shellItem->Release(); - } else if (SUCCEEDED(collectionItem->QueryInterface(qIID_IShellLinkW, reinterpret_cast<void **>(&shellLink)))) { - jumplistItem = fromIShellLink(shellLink); - shellLink->Release(); - } else { - qWarning("QWinJumpList: object of unexpected class found"); - } - collectionItem->Release(); - if (jumplistItem) - list.append(jumplistItem); - } - return list; -} - -IObjectCollection *QWinJumpListPrivate::toComCollection(const QList<QWinJumpListItem *> &list) -{ - if (list.isEmpty()) - return nullptr; - IObjectCollection *collection = nullptr; - HRESULT hresult = CoCreateInstance(qCLSID_EnumerableObjectCollection, nullptr, CLSCTX_INPROC_SERVER, qIID_IObjectCollection, reinterpret_cast<void **>(&collection)); - if (FAILED(hresult)) { - QWinJumpListPrivate::warning("QWinJumpList: failed to instantiate IObjectCollection", hresult); - return nullptr; - } - for (QWinJumpListItem *item : list) { - IUnknown *iitem = toICustomDestinationListItem(item); - if (iitem) { - collection->AddObject(iitem); - iitem->Release(); - } - } - return collection; -} - -QWinJumpListItem *QWinJumpListPrivate::fromIShellLink(IShellLinkW *link) -{ - auto *item = new QWinJumpListItem(QWinJumpListItem::Link); - - IPropertyStore *linkProps; - link->QueryInterface(qIID_IPropertyStore, reinterpret_cast<void **>(&linkProps)); - PROPVARIANT var; - linkProps->GetValue(qPKEY_Link_Arguments, &var); - item->setArguments(QStringList(QString::fromWCharArray(var.pwszVal))); - PropVariantClear(&var); - linkProps->Release(); - - const int buffersize = 2048; - wchar_t buffer[buffersize]; - - link->GetDescription(buffer, INFOTIPSIZE); - item->setDescription(QString::fromWCharArray(buffer)); - - int dummyindex; - link->GetIconLocation(buffer, buffersize-1, &dummyindex); - item->setIcon(QIcon(QString::fromWCharArray(buffer))); - - link->GetPath(buffer, buffersize-1, 0, 0); - item->setFilePath(QDir::fromNativeSeparators(QString::fromWCharArray(buffer))); - - return item; -} - -QWinJumpListItem *QWinJumpListPrivate::fromIShellItem(IShellItem2 *shellitem) -{ - auto *item = new QWinJumpListItem(QWinJumpListItem::Destination); - wchar_t *strPtr; - shellitem->GetDisplayName(SIGDN_FILESYSPATH, &strPtr); - item->setFilePath(QDir::fromNativeSeparators(QString::fromWCharArray(strPtr))); - CoTaskMemFree(strPtr); - return item; -} - -IUnknown *QWinJumpListPrivate::toICustomDestinationListItem(const QWinJumpListItem *item) -{ - switch (item->type()) { - case QWinJumpListItem::Destination : - return toIShellItem(item); - case QWinJumpListItem::Link : - return toIShellLink(item); - case QWinJumpListItem::Separator : - return makeSeparatorShellItem(); - default: - return nullptr; - } -} - -IShellLinkW *QWinJumpListPrivate::toIShellLink(const QWinJumpListItem *item) -{ - IShellLinkW *link = nullptr; - HRESULT hresult = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, qIID_IShellLinkW, reinterpret_cast<void **>(&link)); - if (FAILED(hresult)) { - QWinJumpListPrivate::warning("QWinJumpList: failed to instantiate IShellLinkW", hresult); - return nullptr; - } - - const QString args = createArguments(item->arguments()); - const int iconPathSize = QWinJumpListPrivate::iconsDirPath().size() - + int(sizeof(void *)) * 2 + 4; // path + ptr-name-in-hex + .ico - const int bufferSize = qMax(args.size(), - qMax(item->workingDirectory().size(), - qMax(item->description().size(), - qMax(item->title().size(), - qMax(item->filePath().size(), iconPathSize))))) + 1; - auto *buffer = new wchar_t[bufferSize]; - - if (!item->description().isEmpty()) { - qt_qstringToNullTerminated(item->description(), buffer); - link->SetDescription(buffer); - } - - qt_qstringToNullTerminated(item->filePath(), buffer); - link->SetPath(buffer); - - if (!item->workingDirectory().isEmpty()) { - qt_qstringToNullTerminated(item->workingDirectory(), buffer); - link->SetWorkingDirectory(buffer); - } - - qt_qstringToNullTerminated(args, buffer); - link->SetArguments(buffer); - - if (!item->icon().isNull()) { - QString iconPath = QWinJumpListPrivate::iconsDirPath() + QString::number(reinterpret_cast<quintptr>(item), 16) + QLatin1String(".ico"); - bool iconSaved = item->icon().pixmap(GetSystemMetrics(SM_CXICON)).save(iconPath, "ico"); - if (iconSaved) { - qt_qstringToNullTerminated(iconPath, buffer); - link->SetIconLocation(buffer, 0); - } - } - - IPropertyStore *properties; - PROPVARIANT titlepv; - hresult = link->QueryInterface(qIID_IPropertyStore, reinterpret_cast<void **>(&properties)); - if (FAILED(hresult)) { - link->Release(); - return nullptr; - } - - qt_qstringToNullTerminated(item->title(), buffer); - InitPropVariantFromString(buffer, &titlepv); - properties->SetValue(qPKEY_Title, titlepv); - properties->Commit(); - properties->Release(); - PropVariantClear(&titlepv); - - delete[] buffer; - return link; -} - -IShellItem2 *QWinJumpListPrivate::toIShellItem(const QWinJumpListItem *item) -{ - IShellItem2 *shellitem = nullptr; - QScopedArrayPointer<wchar_t> buffer(qt_qstringToNullTerminated(item->filePath())); - SHCreateItemFromParsingName(buffer.data(), nullptr, qIID_IShellItem2, reinterpret_cast<void **>(&shellitem)); - return shellitem; -} - -IShellLinkW *QWinJumpListPrivate::makeSeparatorShellItem() -{ - IShellLinkW *separator; - HRESULT res = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, qIID_IShellLinkW, reinterpret_cast<void **>(&separator)); - if (FAILED(res)) - return nullptr; - - IPropertyStore *properties; - res = separator->QueryInterface(qIID_IPropertyStore, reinterpret_cast<void **>(&properties)); - if (FAILED(res)) { - separator->Release(); - return nullptr; - } - - PROPVARIANT isSeparator; - InitPropVariantFromBoolean(TRUE, &isSeparator); - properties->SetValue(qPKEY_AppUserModel_IsDestListSeparator, isSeparator); - properties->Commit(); - properties->Release(); - PropVariantClear(&isSeparator); - - return separator; -} - -/*! - Constructs a QWinJumpList with the parent object \a parent. - */ -QWinJumpList::QWinJumpList(QObject *parent) : - QObject(parent), d_ptr(new QWinJumpListPrivate) -{ - Q_D(QWinJumpList); - d->q_ptr = this; - HRESULT hresult = CoCreateInstance(qCLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER, qIID_ICustomDestinationList, reinterpret_cast<void **>(&d_ptr->pDestList)); - if (FAILED(hresult)) - QWinJumpListPrivate::warning("CoCreateInstance", hresult); - d->invalidate(); -} - -/*! - Destroys the QWinJumpList. - */ -QWinJumpList::~QWinJumpList() -{ - Q_D(QWinJumpList); - if (d->dirty) - d->_q_rebuild(); - if (d->pDestList) { - d->pDestList->Release(); - d->pDestList = nullptr; - } - d->destroy(); -} - -/*! - \property QWinJumpList::identifier - \brief the jump list identifier - - Specifies an optional explicit unique identifier for the - application jump list. - - The default value is empty; a system-defined internal identifier - is used instead. See \l {Application User Model IDs} on MSDN for - further details. - - \note The identifier cannot have more than \c 128 characters and - cannot contain spaces. A too long identifier is automatically truncated - to \c 128 characters, and spaces are replaced by underscores. - */ -QString QWinJumpList::identifier() const -{ - Q_D(const QWinJumpList); - return d->identifier; -} - -void QWinJumpList::setIdentifier(const QString &identifier) -{ - Q_D(QWinJumpList); - QString id = identifier; - id.replace(u' ', u'_'); - if (id.size() > 128) - id.truncate(128); - if (d->identifier != id) { - d->identifier = id; - d->invalidate(); - } -} - -/*! - Returns the recent items category in the jump list. - */ -QWinJumpListCategory *QWinJumpList::recent() const -{ - Q_D(const QWinJumpList); - if (!d->recent) { - auto *that = const_cast<QWinJumpList *>(this); - that->d_func()->recent = QWinJumpListCategoryPrivate::create(QWinJumpListCategory::Recent, that); - } - return d->recent; -} - -/*! - Returns the frequent items category in the jump list. - */ -QWinJumpListCategory *QWinJumpList::frequent() const -{ - Q_D(const QWinJumpList); - if (!d->frequent) { - auto *that = const_cast<QWinJumpList *>(this); - that->d_func()->frequent = QWinJumpListCategoryPrivate::create(QWinJumpListCategory::Frequent, that); - } - return d->frequent; -} - -/*! - Returns the tasks category in the jump list. - */ -QWinJumpListCategory *QWinJumpList::tasks() const -{ - Q_D(const QWinJumpList); - if (!d->tasks) { - auto *that = const_cast<QWinJumpList *>(this); - that->d_func()->tasks = QWinJumpListCategoryPrivate::create(QWinJumpListCategory::Tasks, that); - } - return d->tasks; -} - -/*! - Returns the custom categories in the jump list. - */ -QList<QWinJumpListCategory *> QWinJumpList::categories() const -{ - Q_D(const QWinJumpList); - return d->categories; -} - -/*! - Adds a custom \a category to the jump list. - */ -void QWinJumpList::addCategory(QWinJumpListCategory *category) -{ - Q_D(QWinJumpList); - if (!category) - return; - - QWinJumpListCategoryPrivate::get(category)->jumpList = this; - d->categories.append(category); - d->invalidate(); -} - -/*! - \overload addCategory() - Creates a custom category with provided \a title and optional \a items, - and adds it to the jump list. - */ -QWinJumpListCategory *QWinJumpList::addCategory(const QString &title, const QList<QWinJumpListItem *> items) -{ - auto *category = new QWinJumpListCategory(title); - for (QWinJumpListItem *item : items) - category->addItem(item); - addCategory(category); - return category; -} - -/*! - Clears the jump list. - - \sa QWinJumpListCategory::clear() - */ -void QWinJumpList::clear() -{ - Q_D(QWinJumpList); - recent()->clear(); - frequent()->clear(); - if (d->tasks) - d->tasks->clear(); - for (QWinJumpListCategory *category : qAsConst(d->categories)) - category->clear(); - d->destroy(); -} - -#ifndef QT_NO_DEBUG_STREAM - -QDebug operator<<(QDebug debug, const QWinJumpList *jumplist) -{ - QDebugStateSaver saver(debug); - debug.nospace(); - debug.noquote(); - debug << "QWinJumpList("; - if (jumplist) { - debug << "(identifier=\"" << jumplist->identifier() << "\", recent=" - << jumplist->recent() << ", frequent=" << jumplist->frequent() - << ", tasks=" << jumplist->tasks() - << ", categories=" << jumplist->categories(); - } else { - debug << '0'; - } - debug << ')'; - return debug; -} -#endif // !QT_NO_DEBUG_STREAM - -QT_END_NAMESPACE - -#include "moc_qwinjumplist.cpp" |