mirror of
https://github.com/ONLYOFFICE/desktop-apps.git
synced 2026-02-10 18:05:16 +08:00
Merge pull request #938 from ONLYOFFICE/feature/jumplist_recent_63817
Add feature 63817
This commit is contained in:
@ -47,6 +47,7 @@ build_xp {
|
||||
DEFINES += __OS_WIN_XP
|
||||
} else {
|
||||
HEADERS += $$PWD/src/jumplist.h
|
||||
SOURCES += $$PWD/src/jumplist.cpp
|
||||
LIBS += -lshlwapi \
|
||||
-lole32
|
||||
}
|
||||
|
||||
194
win-linux/extras/projicons/src/jumplist.cpp
Normal file
194
win-linux/extras/projicons/src/jumplist.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* (c) Copyright Ascensio System SIA 2010-2019
|
||||
*
|
||||
* This program is a free software product. You can redistribute it and/or
|
||||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||||
* version 3 as published by the Free Software Foundation. In accordance with
|
||||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||||
* of any third-party rights.
|
||||
*
|
||||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
*
|
||||
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
|
||||
* street, Riga, Latvia, EU, LV-1050.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of the Program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU AGPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||||
* grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||||
* well as technical writing content are licensed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
*
|
||||
*/
|
||||
|
||||
#define NTDDI_VERSION NTDDI_WIN7
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define STRICT_TYPED_ITEMIDS
|
||||
#define ICON_OFFSET 14
|
||||
|
||||
#include "jumplist.h"
|
||||
#include <QtGlobal>
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include <objectarray.h>
|
||||
#include <shobjidl.h>
|
||||
#include <propkey.h>
|
||||
#include <propvarutil.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
|
||||
HRESULT _CreateShellLink(PCWSTR pszArguments, PCWSTR pszTitle, IShellLink **ppsl, int index)
|
||||
{
|
||||
IShellLink *psl;
|
||||
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&psl));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WCHAR szAppPath[MAX_PATH];
|
||||
if (GetModuleFileName(NULL, szAppPath, ARRAYSIZE(szAppPath)))
|
||||
{
|
||||
hr = psl->SetPath(szAppPath);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->SetArguments(pszArguments);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->SetIconLocation(szAppPath, index + ICON_OFFSET);
|
||||
Q_UNUSED(hr);
|
||||
IPropertyStore *pps;
|
||||
hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PROPVARIANT propvar;
|
||||
hr = InitPropVariantFromString(pszTitle, &propvar);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pps->SetValue(PKEY_Title, propvar);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pps->Commit();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->QueryInterface(IID_PPV_ARGS(ppsl));
|
||||
}
|
||||
}
|
||||
PropVariantClear(&propvar);
|
||||
}
|
||||
pps->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
psl->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT _AddTasksToList(ICustomDestinationList *pcdl, QStringList list)
|
||||
{
|
||||
IObjectCollection *poc;
|
||||
HRESULT hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PCWSTR args[] = {
|
||||
L"--new:word",
|
||||
L"--new:cell",
|
||||
L"--new:slide",
|
||||
L"--new:form"
|
||||
};
|
||||
|
||||
IShellLink * psl;
|
||||
for (int i = 0; i < MAX_TASK_NUM && i < list.size(); i++) {
|
||||
hr = _CreateShellLink(args[i], list[i].replace('_', ' ').toStdWString().c_str(), &psl, i);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = poc->AddObject(psl);
|
||||
psl->Release();
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IObjectArray * poa;
|
||||
hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pcdl->AddUserTasks(poa);
|
||||
poa->Release();
|
||||
}
|
||||
}
|
||||
poc->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CreateJumpList(const QStringList &list)
|
||||
{
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ICustomDestinationList *pcdl;
|
||||
hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
|
||||
if (SUCCEEDED(hr)) {
|
||||
UINT cMinSlots;
|
||||
IObjectArray *poaRemoved;
|
||||
hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = _AddTasksToList(pcdl, list);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = pcdl->CommitList();
|
||||
}
|
||||
poaRemoved->Release();
|
||||
pcdl->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
|
||||
void DeleteJumpList()
|
||||
{
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ICustomDestinationList *pcdl;
|
||||
hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pcdl->DeleteList(NULL);
|
||||
pcdl->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
|
||||
void ClearHistory()
|
||||
{
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IApplicationDestinations *pad;
|
||||
hr = CoCreateInstance(CLSID_ApplicationDestinations, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pad));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pad->RemoveAllDestinations();
|
||||
pad->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
@ -1,146 +1,45 @@
|
||||
/*
|
||||
* (c) Copyright Ascensio System SIA 2010-2019
|
||||
*
|
||||
* This program is a free software product. You can redistribute it and/or
|
||||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||||
* version 3 as published by the Free Software Foundation. In accordance with
|
||||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||||
* of any third-party rights.
|
||||
*
|
||||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
*
|
||||
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
|
||||
* street, Riga, Latvia, EU, LV-1050.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of the Program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU AGPL version 3.
|
||||
*
|
||||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||||
* grant you any rights under trademark law for use of our trademarks.
|
||||
*
|
||||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||||
* well as technical writing content are licensed under the terms of the
|
||||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef JUMPLIST_H
|
||||
#define JUMPLIST_H
|
||||
|
||||
#define NTDDI_VERSION NTDDI_WIN7
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define STRICT_TYPED_ITEMIDS
|
||||
#define ICON_OFFSET 14
|
||||
#include <QStringList>
|
||||
|
||||
#define MIN_TASK_NUM 3
|
||||
#define MAX_TASK_NUM 4
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QStringList>
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include <objectarray.h>
|
||||
#include <shobjidl.h>
|
||||
#include <propkey.h>
|
||||
#include <propvarutil.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
|
||||
HRESULT _CreateShellLink(PCWSTR pszArguments, PCWSTR pszTitle, IShellLink **ppsl, int index)
|
||||
{
|
||||
IShellLink *psl;
|
||||
HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&psl));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WCHAR szAppPath[MAX_PATH];
|
||||
if (GetModuleFileName(NULL, szAppPath, ARRAYSIZE(szAppPath)))
|
||||
{
|
||||
hr = psl->SetPath(szAppPath);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->SetArguments(pszArguments);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->SetIconLocation(szAppPath, index + ICON_OFFSET);
|
||||
Q_UNUSED(hr);
|
||||
IPropertyStore *pps;
|
||||
hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PROPVARIANT propvar;
|
||||
hr = InitPropVariantFromString(pszTitle, &propvar);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pps->SetValue(PKEY_Title, propvar);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pps->Commit();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = psl->QueryInterface(IID_PPV_ARGS(ppsl));
|
||||
}
|
||||
}
|
||||
PropVariantClear(&propvar);
|
||||
}
|
||||
pps->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
psl->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT _AddTasksToList(ICustomDestinationList *pcdl, QStringList list)
|
||||
{
|
||||
IObjectCollection *poc;
|
||||
HRESULT hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
PCWSTR args[] = {
|
||||
L"--new:word",
|
||||
L"--new:cell",
|
||||
L"--new:slide",
|
||||
L"--new:form"
|
||||
};
|
||||
|
||||
IShellLink * psl;
|
||||
for (int i = 0; i < MAX_TASK_NUM && i < list.size(); i++) {
|
||||
hr = _CreateShellLink(args[i], list[i].replace('_', ' ').toStdWString().c_str(), &psl, i);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = poc->AddObject(psl);
|
||||
psl->Release();
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IObjectArray * poa;
|
||||
hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pcdl->AddUserTasks(poa);
|
||||
poa->Release();
|
||||
}
|
||||
}
|
||||
poc->Release();
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
void CreateJumpList(const QStringList &list)
|
||||
{
|
||||
ICustomDestinationList *pcdl;
|
||||
HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
|
||||
if (SUCCEEDED(hr)) {
|
||||
UINT cMinSlots;
|
||||
IObjectArray *poaRemoved;
|
||||
hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = _AddTasksToList(pcdl, list);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = pcdl->CommitList();
|
||||
}
|
||||
}
|
||||
poaRemoved->Release();
|
||||
pcdl->Release();
|
||||
}
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
|
||||
void DeleteJumpList()
|
||||
{
|
||||
ICustomDestinationList *pcdl;
|
||||
HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pcdl->DeleteList(NULL);
|
||||
pcdl->Release();
|
||||
}
|
||||
Q_UNUSED(hr);
|
||||
}
|
||||
void CreateJumpList(const QStringList &list);
|
||||
void DeleteJumpList();
|
||||
void ClearHistory();
|
||||
|
||||
#endif // JUMPLIST_H
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
#include "Windows.h"
|
||||
#ifndef __OS_WIN_XP
|
||||
# include "jumplist.h"
|
||||
# include <shlobj_core.h>
|
||||
#endif
|
||||
|
||||
typedef HRESULT (__stdcall *SetCurrentProcessExplicitAppUserModelIDProc)(PCWSTR AppID);
|
||||
@ -82,8 +83,14 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
} else
|
||||
if (_cmdArgs.contains("--remove-jump-list")) {
|
||||
ClearHistory();
|
||||
DeleteJumpList();
|
||||
return 0;
|
||||
} else
|
||||
if (_cmdArgs.contains("--add-to-recent") && _cmdArgs.size() > 1) {
|
||||
std::wstring path = _cmdArgs.at(1).toStdWString();
|
||||
SHAddToRecentDocs(SHARD_PATHW, path.c_str());
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -232,6 +232,9 @@ public:
|
||||
CMessage::error(m_appmanager.mainWindow()->handle(),
|
||||
QObject::tr("File %1 cannot be opened or doesn't exists.").arg(_info.fileName()));
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else Utils::addToRecent(file_path);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,6 +50,8 @@
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (argc > 1 && strcmp(argv[1], "--add-to-recent") == 0)
|
||||
return 0;
|
||||
Core_SetProcessDpiAwareness();
|
||||
Utils::setAppUserModelId(APP_USER_MODEL_ID);
|
||||
WCHAR * cm_line = GetCommandLine();
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
#include <QScreen>
|
||||
#include <QStorageInfo>
|
||||
#include <QPrinterInfo>
|
||||
#include <QProcess>
|
||||
#include "cascapplicationmanagerwrapper.h"
|
||||
#include "qdpichecker.h"
|
||||
#include "common/File.h"
|
||||
@ -55,7 +56,6 @@
|
||||
#include "lmcons.h"
|
||||
typedef HRESULT (__stdcall *SetCurrentProcessExplicitAppUserModelIDProc)(PCWSTR AppID);
|
||||
#else
|
||||
# include <QProcess>
|
||||
# include <QEventLoop>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
@ -728,6 +728,13 @@ Utils::WinVer Utils::getWinVersion()
|
||||
}
|
||||
return WinVer::Undef;
|
||||
}
|
||||
|
||||
void Utils::addToRecent(const std::wstring &path)
|
||||
{
|
||||
QString _path = QString::fromStdWString(path);
|
||||
QString appPath = qApp->applicationDirPath();
|
||||
QProcess::startDetached(appPath + "/" + QString(REG_APP_NAME), {"--add-to-recent", QDir::toNativeSeparators(_path)}, appPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
QString Utils::replaceBackslash(const QString& path)
|
||||
|
||||
@ -122,6 +122,7 @@ public:
|
||||
Undef, WinXP, WinVista, Win7, Win8, Win8_1, Win10, Win11
|
||||
};
|
||||
static WinVer getWinVersion();
|
||||
static void addToRecent(const std::wstring&);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -707,6 +707,9 @@ void CMainWindow::doOpenLocalFile(COpenOptions& opts)
|
||||
int result = m_pTabs->openLocalDocument(opts, true);
|
||||
if ( !(result < 0) ) {
|
||||
toggleButtonMain(false, true);
|
||||
#ifdef _WIN32
|
||||
Utils::addToRecent(opts.wurl);
|
||||
#endif
|
||||
} else
|
||||
if (result == -255) {
|
||||
QTimer::singleShot(0, this, [=] {
|
||||
|
||||
Reference in New Issue
Block a user