Skip to content

Commit

Permalink
Add registerUriScheme() to qx-system
Browse files Browse the repository at this point in the history
  • Loading branch information
oblivioncth committed Oct 19, 2023
1 parent 13553a0 commit dff2019
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lib/core/include/qx/core/qx-system.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ QX_CORE_EXPORT SystemError cleanKillProcess(quint32 processId);
QX_CORE_EXPORT SystemError forceKillProcess(quint32 processId);

QX_CORE_EXPORT bool enforceSingleInstance(QString uniqueAppId);

QX_CORE_EXPORT bool registerUriScheme(const QString& scheme, const QString& name, const QString& command);
}

#endif // QX_SYSTEM_H
13 changes: 13 additions & 0 deletions lib/core/src/qx-system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,17 @@ bool processIsRunning(quint32 processId) { return processName(processId).isNull(
* changed in future revisions once set.
*/

/*!
* @fn bool registerUriScheme(const QString& scheme, const QString& command)
*
* Registers the custom URI scheme @a scheme, with user facing name @a name, to the system.
* The scheme is configued so that when a URL that uses the scheme is followed, the command @a
* command will be executed with the scheme URL automatically passed as the last argument.
*
* @a scheme cannot contain whitespace.
*
* @note On Linux this function only works for distibutions that can utilize FreeDesktop
* XDG Desktop Entries.
*/

}
39 changes: 39 additions & 0 deletions lib/core/src/qx-system_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#include <QFile>
#include <QDir>
#include <QDirIterator>
#include <QSettings>
#include <QProcess>
#include <QStandardPaths>

// Inner-component Includes
#include <qx/core/qx-regularexpression.h>
Expand Down Expand Up @@ -297,4 +300,40 @@ bool enforceSingleInstance(QString uniqueAppId)
return true;
}

bool registerUriScheme(const QString& scheme, const QString& name, const QString& command)
{
if(scheme.contains(QChar::Space))
return false;

// Get desktop entry path
QString XDG_DATA_HOME = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
QString dEntryFilename = scheme + u"-scheme-handler.desktop"_s;
QString dEntryPath = XDG_DATA_HOME + u"/applications/"_s + dEntryFilename;
QString xSchemeHandler = u"x-scheme-handler/"_s + scheme;

// Create desktop entry
QSettings de(dEntryPath, QSettings::IniFormat);
de.beginGroup(u"Desktop Entry"_s);
de.setValue(u"Type"_s, u"Application"_s);
de.setValue(u"Name"_s, name);
de.setValue(u"Exec"_s, command + u" %u"_s); // %u is already passed as single param, no need for quotes
de.setValue(u"StartupNotify"_s, u"false"_s);
de.setValue(u"MimeType"_s, xSchemeHandler);
de.endGroup();

de.sync();
if(de.status() != QSettings::NoError)
return false;

// Register MIME type
QProcess xdgMime;
xdgMime.setProgram(u"xdg-mime"_s);
xdgMime.setArguments({u"default"_s, dEntryFilename, xSchemeHandler});
xdgMime.setStandardOutputFile(QProcess::nullDevice());
xdgMime.setStandardErrorFile(QProcess::nullDevice());
xdgMime.start();

return xdgMime.waitForFinished(3000) && xdgMime.exitStatus() == xdgMime.NormalExit && xdgMime.exitCode() == 0;
}

}
23 changes: 23 additions & 0 deletions lib/core/src/qx-system_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QFile>
#include <QDir>
#include <QDirIterator>
#include <QSettings>

// Extra-component Includes
#include "qx/core/qx-integrity.h"
Expand Down Expand Up @@ -223,4 +224,26 @@ bool enforceSingleInstance(QString uniqueAppId)
return createMutex(hashId);
}

bool registerUriScheme(const QString& scheme, const QString& name, const QString& command)
{
if(scheme.contains(QChar::Space))
return false;

// Set registry keys
QSettings schemeKey(u"HKEY_CLASSES_ROOT\\"_s + scheme, QSettings::NativeFormat);
schemeKey.setValue(u"."_s, name);
schemeKey.setValue("URL Protocol", "");
schemeKey.setValue(u"shell/open/command/."_s, command + uR"( "%1")"_s);

// Save and return status
schemeKey.sync();
return schemeKey.status() == QSettings::NoError;

/* NOTE: The Microsoft specification recommends adding a DefaultIcon key to these entries
* with an executable based icon path, though I'm not sure if/how that's actually
* used. If that is ever added, we should check if adding an icon to the desktop entry
* of the Linux equivalent has an appreciable effect as well.
*/
}

}

0 comments on commit dff2019

Please sign in to comment.