Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ What gets stored (if allowed): cookies.
| Take snapshot | `Ctrl`+`T` | |
| Take full-page snapshot | `Ctrl`+`Shift`+`T` | |
| Take vector snapshot (SVG) | `Ctrl`+`Shift`+`S` | |
| Save page | `Ctrl`+`S` | |
| Toggle window size lock | `Ctrl`+`L` | |
| Toggle mute | `Ctrl`+`M` | |
| Refresh current page | `Ctrl`+`R` | |
Expand All @@ -70,6 +71,9 @@ What gets stored (if allowed): cookies.
| Go back | `Ctrl`+`←` | `Backspace` |
| Go forward | `Ctrl`+`→` | |
| Open link using default web browser | `Ctrl`+_click_ | |
| Edit app settings | `Ctrl`+`,` | |

Most of these can also be found in the right-click menu.


## Working with the codebase
Expand Down
3 changes: 3 additions & 0 deletions inc/liquid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class Liquid
static QString getUniqueFilePath(const QString dirPath, const QString baseName, const QString extension);
static void removeDesktopFile(const QString liquidAppName);
static void runLiquidApp(const QString liquidAppName, const QString activationToken = QString());
// For Liquid apps restarting themselves: they get run again once this program is done (and is no longer in the way)
static void requestRestart(const QString liquidAppName);
static QString getRequestedRestart(void);
static void sleep(const int ms);
static void updateDesktopFileIcon(const QString liquidAppName);
};
7 changes: 7 additions & 0 deletions inc/liquidappconfigwindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ class LiquidAppConfigDialog : public QDialog
bool isPlanningToRun(void);
void setPlanningToRun(const bool state);

// When opened by the Liquid app itself, the dialog doesn't apply saved settings to it (the Liquid app does that)
void setOpenedFromLiquidApp(const bool state);
// Whether saved settings can only take effect once the Liquid app restarts
bool isRestartRequired(void);

public slots:
void save();
void reject() override;
Expand All @@ -38,6 +43,8 @@ public slots:

bool isEditingExistingBool = false;
bool isPlanningToRunBool = false;
bool isOpenedFromLiquidAppBool = false;
bool isRestartRequiredBool = false;

// Connection to the Liquid app being edited (if running), for previewing changes
QLocalSocket* liquidAppConnection = Q_NULLPTR;
Expand Down
10 changes: 6 additions & 4 deletions inc/liquidappwindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <QCoreApplication>
#include <QImage>
#include <QMenu>
#include <QPointer>
#include <QNetworkProxy>
#include <QSettings>
#include <QShortcut>
Expand Down Expand Up @@ -78,6 +79,7 @@ public slots:
void waitForNextFrame(void);
bool waitForDocumentToFinishLoading(void);
void applyIcon(void);
void editSettings(void);
void maybeFetchIcon(void);
void useFetchedIcon(const LiquidAppIcon& icon);
bool isShowingOwnWebsite(void);
Expand All @@ -92,6 +94,9 @@ public slots:
LiquidAppIconFetcher* iconFetcher = Q_NULLPTR;
bool iconFetchAttempted = false;

// Settings dialog, while it's open
QPointer<QDialog> settingsDialog;

LiquidAppWebPage* liquidAppWebPage = Q_NULLPTR;
QWebEngineProfile* liquidAppWebProfile = Q_NULLPTR;
QWebEngineSettings* liquidAppWebSettings = Q_NULLPTR;
Expand Down Expand Up @@ -122,6 +127,7 @@ public slots:
QAction* reloadAction;
QAction* reloadAction2;
QAction* savePageAction;
QAction* editSettingsAction;
QAction* stopLoadingOrExitFullScreenModeAction;
QAction* takeSnapshotAction;
QAction* takeSnapshotFullPageAction;
Expand All @@ -139,10 +145,6 @@ public slots:
// Context menu and its actions
QMenu* contextMenu;
QAction* contextMenuCopyUrlAction;
QAction* contextMenuReloadAction;
QAction* contextMenuBackAction;
QAction* contextMenuForwardAction;
QAction* contextMenuCloseAction;

// Camera flash effect for snapshots
SnapshotFlashOverlay* snapshotFlashOverlay = Q_NULLPTR;
Expand Down
1 change: 1 addition & 0 deletions inc/lqd.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@
#define LQD_KBD_SEQ_QUIT "Ctrl+Q"
#define LQD_KBD_SEQ_QUIT_2 "Ctrl+W"
#define LQD_KBD_SEQ_SAVE_PAGE "Ctrl+S"
#define LQD_KBD_SEQ_EDIT_SETTINGS "Ctrl+,"
#define LQD_KBD_SEQ_TAKE_SNAPSHOT_VECTOR "Ctrl+Shift+S"
#define LQD_KBD_SEQ_ZOOM_LVL_INC "Ctrl+="
#define LQD_KBD_SEQ_ZOOM_LVL_INC_FINE "Ctrl+Shift+="
Expand Down
12 changes: 12 additions & 0 deletions src/liquid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,18 @@ QByteArray Liquid::makeRaiseMessage(const QString& activationToken)
return message;
}

static QString liquidAppToRestart;

void Liquid::requestRestart(const QString liquidAppName)
{
liquidAppToRestart = liquidAppName;
}

QString Liquid::getRequestedRestart(void)
{
return liquidAppToRestart;
}

void Liquid::sleep(const int ms)
{
// Keep processing events while waiting, but without spinning the CPU:
Expand Down
15 changes: 14 additions & 1 deletion src/liquidappconfigwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,10 @@ void LiquidAppConfigDialog::save()
if (isEditingExistingBool) {
const QString instanceId = LQD_INSTANCE_ID_APP_PREFIX + appName;

if (getSettingsRequiringRestart(tempLiquidAppConfig) != settingsRequiringRestartBefore) {
if (isOpenedFromLiquidAppBool) {
// The Liquid app can't be told to quit (and be waited for) from within itself, it takes care of it on its own
isRestartRequiredBool = getSettingsRequiringRestart(tempLiquidAppConfig) != settingsRequiringRestartBefore;
} else if (getSettingsRequiringRestart(tempLiquidAppConfig) != settingsRequiringRestartBefore) {
// Restart it (wait for it to quit first, it's not possible to have two instances running at once)
if (SingleInstance::sendMessage(instanceId, LQD_INSTANCE_MSG_QUIT)) {
QElapsedTimer timer;
Expand Down Expand Up @@ -1397,3 +1400,13 @@ void LiquidAppConfigDialog::setPlanningToRun(const bool state)
}
}
}

void LiquidAppConfigDialog::setOpenedFromLiquidApp(const bool state)
{
isOpenedFromLiquidAppBool = state;
}

bool LiquidAppConfigDialog::isRestartRequired(void)
{
return isRestartRequiredBool;
}
119 changes: 101 additions & 18 deletions src/liquidappwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "liquid.hpp"
#include "liquidappfile.hpp"
#include "liquidappicon.hpp"
#include "liquidappconfigwindow.hpp"
#include "liquidappcookiejar.hpp"
#include "liquidappwebpage.hpp"
#include "liquidappwindow.hpp"
Expand Down Expand Up @@ -418,6 +419,12 @@ void LiquidAppWindow::bindKeyboardShortcuts(void)
addAction(takeSnapshotVectorAction);
connect(takeSnapshotVectorAction, &QAction::triggered, this, &LiquidAppWindow::takeVectorSnapshot);

// Connect "edit settings" shortcut
editSettingsAction = new QAction;
editSettingsAction->setShortcut(QKeySequence(tr(LQD_KBD_SEQ_EDIT_SETTINGS)));
addAction(editSettingsAction);
connect(editSettingsAction, &QAction::triggered, this, &LiquidAppWindow::editSettings);

// Connect "save page" shortcut
savePageAction = new QAction;
savePageAction->setShortcut(QKeySequence(tr(LQD_KBD_SEQ_SAVE_PAGE)));
Expand Down Expand Up @@ -457,6 +464,11 @@ void LiquidAppWindow::closeEvent(QCloseEvent* event)
return;
}

// Settings being edited (e.g. when told to quit by the main window) get discarded, and their preview undone
if (settingsDialog) {
settingsDialog->reject();
}

event->accept();
deleteLater();
}
Expand All @@ -465,10 +477,22 @@ void LiquidAppWindow::contextMenuEvent(QContextMenuEvent* event)
{
Q_UNUSED(event);

contextMenuBackAction->setEnabled(history()->canGoBack());
contextMenuForwardAction->setEnabled(history()->canGoForward());
// Reflect current state (keyboard shortcuts work regardless, so it's only updated here)
backAction->setEnabled(history()->canGoBack());
forwardAction->setEnabled(history()->canGoForward());
muteAudioAction->setChecked(page()->isAudioMuted());
toggleFullScreenModeAction->setText((isFullScreen()) ? tr("Exit Full Screen") : tr("Enter Full Screen"));
toggleFullScreenModeAction->setIcon(QIcon::fromTheme((isFullScreen()) ? QStringLiteral("view-restore") : QStringLiteral("view-fullscreen")));
toggleGeometryLockAction->setChecked(windowGeometryIsLocked);
toggleGeometryLockAction->setText((windowGeometryIsLocked) ? tr("Unfreeze Frame Size") : tr("Freeze Frame Size"));
toggleGeometryLockAction->setEnabled(!isFullScreen()); // Frame size can't be frozen while in full-screen mode

contextMenu->exec(QCursor::pos());

// Disabled actions don't respond to keyboard shortcuts either, and the state they reflect changes all the time
backAction->setEnabled(true);
forwardAction->setEnabled(true);
toggleGeometryLockAction->setEnabled(true);
}

bool LiquidAppWindow::eventFilter(QObject* watched, QEvent* event)
Expand Down Expand Up @@ -1136,31 +1160,90 @@ void LiquidAppWindow::saveLiquidAppConfig(void)

void LiquidAppWindow::setupContextMenu(void)
{
contextMenu = new QMenu;
contextMenu = new QMenu(this);

contextMenuCopyUrlAction = new QAction(QIcon::fromTheme(QStringLiteral("internet-web-browser")), tr("Copy Current URL"));
contextMenuReloadAction = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), tr("Refresh"));
contextMenuBackAction = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), tr("Go Back"));
contextMenuForwardAction = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), tr("Go Forward"));
contextMenuCloseAction = new QAction(QIcon::fromTheme(QStringLiteral("process-stop")), tr("Quit"));

contextMenu->addAction(contextMenuCopyUrlAction);
contextMenu->addAction(contextMenuReloadAction);
contextMenu->addAction(contextMenuBackAction);
contextMenu->addAction(contextMenuForwardAction);
contextMenu->addAction(contextMenuCloseAction);
// The menu reuses actions behind keyboard shortcuts, which makes it show the shortcuts next to them
const auto present = [](QAction* action, const char* const iconName, const QString& text) {
action->setIcon(QIcon::fromTheme(QLatin1String(iconName)));
action->setText(text);
action->setShortcutVisibleInContextMenu(true);
};

contextMenuCopyUrlAction = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), tr("Copy Current URL"), this);
connect(contextMenuCopyUrlAction, &QAction::triggered, this, [this](){
QApplication::clipboard()->setText(page()->url().toString());
});
connect(contextMenuReloadAction, &QAction::triggered, this, &QWebEngineView::reload);
connect(contextMenuBackAction, &QAction::triggered, this, &QWebEngineView::back);
connect(contextMenuForwardAction, &QAction::triggered, this, &QWebEngineView::forward);
connect(contextMenuCloseAction, SIGNAL(triggered()), this, SLOT(close()));

present(backAction, "go-previous", tr("Go Back"));
present(forwardAction, "go-next", tr("Go Forward"));
present(reloadAction, "view-refresh", tr("Refresh"));
present(savePageAction, "document-save", tr("Save Page"));
present(takeSnapshotAction, "camera-photo", tr("Take Screenshot"));
present(takeSnapshotFullPageAction, "camera-photo", tr("Take Full-Page Screenshot"));
present(takeSnapshotVectorAction, "image-x-generic", tr("Save as Vector Image"));
present(muteAudioAction, "audio-volume-muted", tr("Mute Audio"));
present(toggleFullScreenModeAction, "view-fullscreen", tr("Enter Full Screen"));
present(toggleGeometryLockAction, "object-locked", tr("Freeze Frame Size"));
present(editSettingsAction, "preferences-system", tr("Settings…"));
present(quitAction, "application-exit", tr("Quit"));

muteAudioAction->setCheckable(true);
toggleGeometryLockAction->setCheckable(true);

contextMenu->addAction(backAction);
contextMenu->addAction(forwardAction);
contextMenu->addAction(reloadAction);
contextMenu->addSeparator();
contextMenu->addAction(contextMenuCopyUrlAction);
contextMenu->addAction(savePageAction);
contextMenu->addSeparator();
contextMenu->addAction(takeSnapshotAction);
contextMenu->addAction(takeSnapshotFullPageAction);
contextMenu->addAction(takeSnapshotVectorAction);
contextMenu->addSeparator();
contextMenu->addAction(muteAudioAction);
contextMenu->addAction(toggleFullScreenModeAction);
contextMenu->addAction(toggleGeometryLockAction);
contextMenu->addSeparator();
contextMenu->addAction(editSettingsAction);
contextMenu->addAction(quitAction);

setContextMenuPolicy(Qt::DefaultContextMenu);
}

void LiquidAppWindow::editSettings(void)
{
// Only one at a time
if (settingsDialog) {
Liquid::raiseWindow(settingsDialog);
return;
}

LiquidAppConfigDialog dialog(this, liquidAppName);
dialog.setOpenedFromLiquidApp(true);
settingsDialog = &dialog;

// Changes get previewed while editing (the dialog talks to this Liquid app the same way it would from the main window)
const int result = dialog.exec();
settingsDialog = Q_NULLPTR;

if (result != QDialog::Accepted) {
return;
}

if (dialog.isRestartRequired()) {
// Quit (saving everything as usual), and have this program run the Liquid app again on its way out
Liquid::requestRestart(liquidAppName);
close();
return;
}

reloadLiquidAppConfig();

// Let the main window (if it's open) show the icon, in case it's changed
SingleInstance::sendMessage(LQD_INSTANCE_ID_MAIN, QByteArray(LQD_INSTANCE_MSG_ICON_CHANGED) + " " + liquidAppName.toUtf8());
}

void LiquidAppWindow::setForgiveNextPageLoadError(const bool ok)
{
forgiveNextPageLoadError = ok;
Expand Down
6 changes: 6 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,5 +231,11 @@ int main(int argc, char **argv)
singleInstance = Q_NULLPTR;
}

// A Liquid app that has had settings changed that require it to restart (by now, it's saved everything,
// and no longer claims its instance, so the new one won't mistake it for itself already running)
if (!Liquid::getRequestedRestart().isEmpty()) {
Liquid::runLiquidApp(Liquid::getRequestedRestart());
}

return ret;
}
Loading