Skip to content

Commit

Permalink
Merge pull request #227 from Leo40Git/feature/instance-shortcuts
Browse files Browse the repository at this point in the history
Closes #210
  • Loading branch information
Scrumplex committed Nov 25, 2022
2 parents 5872c34 + ba46ff6 commit fd8b4c5
Show file tree
Hide file tree
Showing 16 changed files with 475 additions and 26 deletions.
187 changes: 161 additions & 26 deletions launcher/FileSystem.cpp
Expand Up @@ -49,6 +49,7 @@
#include "StringUtils.h"

#if defined Q_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <objbase.h>
#include <objidl.h>
#include <shlguid.h>
Expand Down Expand Up @@ -343,12 +344,37 @@ QString getDesktopDir()
}

// Cross-platform Shortcut creation
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString icon)
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
location = PathCombine(location, name + ".desktop");
#if defined(Q_OS_MACOS)
destination += ".command";

QFile f(location);
QFile f(destination);
f.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream stream(&f);

QString argstring;
if (!args.empty())
argstring = " \"" + args.join("\" \"") + "\"";

stream << "#!/bin/bash"
<< "\n";
stream << "\""
<< target
<< "\" "
<< argstring
<< "\n";

stream.flush();
f.close();

f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);

return true;
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
destination += ".desktop";

QFile f(destination);
f.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream stream(&f);

Expand All @@ -360,36 +386,145 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
<< "\n";
stream << "Type=Application"
<< "\n";
stream << "TryExec=" << dest.toLocal8Bit() << "\n";
stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n";
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
stream << "Name=" << name.toLocal8Bit() << "\n";
stream << "Icon=" << icon.toLocal8Bit() << "\n";
if (!icon.isEmpty())
{
stream << "Icon=" << icon.toLocal8Bit() << "\n";
}

stream.flush();
f.close();

f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);

return true;
#elif defined Q_OS_WIN
// TODO: Fix
// QFile file(PathCombine(location, name + ".lnk"));
// WCHAR *file_w;
// WCHAR *dest_w;
// WCHAR *args_w;
// file.fileName().toWCharArray(file_w);
// dest.toWCharArray(dest_w);

// QString argStr;
// for (int i = 0; i < args.count(); i++)
// {
// argStr.append(args[i]);
// argStr.append(" ");
// }
// argStr.toWCharArray(args_w);

// return SUCCEEDED(CreateLink(file_w, dest_w, args_w));
return false;
#elif defined(Q_OS_WIN)
QFileInfo targetInfo(target);

if (!targetInfo.exists())
{
qWarning() << "Target file does not exist!";
return false;
}

target = targetInfo.absoluteFilePath();

if (target.length() >= MAX_PATH)
{
qWarning() << "Target file path is too long!";
return false;
}

if (!icon.isEmpty() && icon.length() >= MAX_PATH)
{
qWarning() << "Icon path is too long!";
return false;
}

destination += ".lnk";

if (destination.length() >= MAX_PATH)
{
qWarning() << "Destination path is too long!";
return false;
}

QString argStr;
int argCount = args.count();
for (int i = 0; i < argCount; i++)
{
if (args[i].contains(' '))
{
argStr.append('"').append(args[i]).append('"');
}
else
{
argStr.append(args[i]);
}

if (i < argCount - 1)
{
argStr.append(" ");
}
}

if (argStr.length() >= MAX_PATH)
{
qWarning() << "Arguments string is too long!";
return false;
}

HRESULT hres;

// ...yes, you need to initialize the entire COM stack just to make a shortcut
hres = CoInitialize(nullptr);
if (FAILED(hres))
{
qWarning() << "Failed to initialize COM!";
return false;
}

WCHAR wsz[MAX_PATH];

IShellLink* psl;

// create an IShellLink instance - this stores the shortcut's attributes
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
wmemset(wsz, 0, MAX_PATH);
target.toWCharArray(wsz);
psl->SetPath(wsz);

wmemset(wsz, 0, MAX_PATH);
argStr.toWCharArray(wsz);
psl->SetArguments(wsz);

wmemset(wsz, 0, MAX_PATH);
targetInfo.absolutePath().toWCharArray(wsz);
psl->SetWorkingDirectory(wsz); // "Starts in" attribute

if (!icon.isEmpty())
{
wmemset(wsz, 0, MAX_PATH);
icon.toWCharArray(wsz);
psl->SetIconLocation(wsz, 0);
}

// query an IPersistFile interface from our IShellLink instance
// this is the interface that will actually let us save the shortcut to disk!
IPersistFile* ppf;
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
wmemset(wsz, 0, MAX_PATH);
destination.toWCharArray(wsz);
hres = ppf->Save(wsz, TRUE);
if (FAILED(hres))
{
qWarning() << "IPresistFile->Save() failed";
qWarning() << "hres = " << hres;
}
ppf->Release();
}
else
{
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
qWarning() << "hres = " << hres;
}
psl->Release();
}
else
{
qWarning() << "Failed to create IShellLink instance";
qWarning() << "hres = " << hres;
}

// go away COM, nobody likes you
CoUninitialize();

return SUCCEEDED(hres);
#else
qWarning("Desktop Shortcuts not supported on your platform!");
return false;
Expand Down
5 changes: 5 additions & 0 deletions launcher/FileSystem.h
Expand Up @@ -172,4 +172,9 @@ QString getDesktopDir();
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path);

/**
* Creates a shortcut to the specified target file at the specified destination path.
*/
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
}
1 change: 1 addition & 0 deletions launcher/resources/OSX/OSX.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>
14 changes: 14 additions & 0 deletions launcher/resources/OSX/scalable/shortcut.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/resources/iOS/iOS.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>
13 changes: 13 additions & 0 deletions launcher/resources/iOS/scalable/shortcut.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/resources/pe_blue/pe_blue.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>
41 changes: 41 additions & 0 deletions launcher/resources/pe_blue/scalable/shortcut.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/resources/pe_colored/pe_colored.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>
13 changes: 13 additions & 0 deletions launcher/resources/pe_colored/scalable/shortcut.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/resources/pe_dark/pe_dark.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>
41 changes: 41 additions & 0 deletions launcher/resources/pe_dark/scalable/shortcut.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions launcher/resources/pe_light/pe_light.qrc
Expand Up @@ -39,5 +39,6 @@
<file>scalable/export.svg</file>
<file>scalable/rename.svg</file>
<file>scalable/launch.svg</file>
<file>scalable/shortcut.svg</file>
</qresource>
</RCC>

0 comments on commit fd8b4c5

Please sign in to comment.