Rewrite shortcuts using QAction.

That way they don't depend on the main window.
This commit is contained in:
John Preston 2023-01-18 11:58:57 +04:00
parent 5154fe0044
commit 3e332ad8e7
4 changed files with 49 additions and 41 deletions

View File

@ -183,9 +183,6 @@ Application::~Application() {
Local::writeSettings();
}
// Depend on primaryWindow() for now :(
Shortcuts::Finish();
_closingAsyncWindows.clear();
_secondaryWindows.clear();
_primaryWindows.clear();
@ -261,6 +258,7 @@ void Application::run() {
Ui::StartCachedCorners();
Ui::Emoji::Init();
Ui::PreloadTextSpoilerMask();
startShortcuts();
startEmojiImageLoader();
startSystemDarkModeViewer();
Media::Player::start(_audio.get());
@ -329,10 +327,7 @@ void Application::run() {
DEBUG_LOG(("Application Info: window created..."));
// Depend on primaryWindow() for now :(
startShortcuts();
startDomain();
startTray();
_lastActivePrimaryWindow->widget()->show();
@ -567,7 +562,7 @@ bool Application::eventFilter(QObject *object, QEvent *e) {
const auto event = static_cast<QShortcutEvent*>(e);
DEBUG_LOG(("Shortcut event caught: %1"
).arg(event->key().toString()));
if (Shortcuts::HandleEvent(event)) {
if (Shortcuts::HandleEvent(object, event)) {
return true;
}
} break;

View File

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h"
#include "base/parse_helper.h"
#include <QAction>
#include <QShortcut>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
@ -143,11 +144,13 @@ public:
void fill();
void clear();
[[nodiscard]] std::vector<Command> lookup(int shortcutId) const;
[[nodiscard]] std::vector<Command> lookup(
not_null<QObject*> object) const;
void toggleMedia(bool toggled);
void toggleSupport(bool toggled);
void listen(not_null<QWidget*> widget);
const QStringList &errors() const;
[[nodiscard]] const QStringList &errors() const;
private:
void fillDefaults();
@ -156,15 +159,15 @@ private:
void set(const QString &keys, Command command, bool replace = false);
void remove(const QString &keys);
void unregister(base::unique_qptr<QShortcut> shortcut);
void unregister(base::unique_qptr<QAction> shortcut);
QStringList _errors;
base::flat_map<QKeySequence, base::unique_qptr<QShortcut>> _shortcuts;
base::flat_multi_map<int, Command> _commandByShortcutId;
base::flat_map<QKeySequence, base::unique_qptr<QAction>> _shortcuts;
base::flat_multi_map<not_null<QObject*>, Command> _commandByObject;
base::flat_set<QShortcut*> _mediaShortcuts;
base::flat_set<QShortcut*> _supportShortcuts;
base::flat_set<QAction*> _mediaShortcuts;
base::flat_set<QAction*> _supportShortcuts;
};
@ -227,7 +230,7 @@ void Manager::fill() {
void Manager::clear() {
_errors.clear();
_shortcuts.clear();
_commandByShortcutId.clear();
_commandByObject.clear();
_mediaShortcuts.clear();
_supportShortcuts.clear();
}
@ -236,11 +239,11 @@ const QStringList &Manager::errors() const {
return _errors;
}
std::vector<Command> Manager::lookup(int shortcutId) const {
std::vector<Command> Manager::lookup(not_null<QObject*> object) const {
auto result = std::vector<Command>();
auto i = _commandByShortcutId.findFirst(shortcutId);
const auto end = _commandByShortcutId.end();
for (; i != end && (i->first == shortcutId); ++i) {
auto i = _commandByObject.findFirst(object);
const auto end = _commandByObject.end();
for (; i != end && (i->first == object); ++i) {
result.push_back(i->second);
}
return result;
@ -258,6 +261,12 @@ void Manager::toggleSupport(bool toggled) {
}
}
void Manager::listen(not_null<QWidget*> widget) {
for (const auto &[keys, shortcut] : _shortcuts) {
widget->addAction(shortcut.get());
}
}
bool Manager::readCustomFile() {
// read custom shortcuts from file if it exists or write an empty custom shortcuts file
QFile file(CustomFilePath());
@ -412,10 +421,10 @@ void Manager::writeDefaultFile() {
shortcuts.push_back(version);
for (const auto &[sequence, shortcut] : _shortcuts) {
const auto shortcutId = shortcut->id();
auto i = _commandByShortcutId.findFirst(shortcutId);
const auto end = _commandByShortcutId.end();
for (; i != end && i->first == shortcutId; ++i) {
const auto object = shortcut.get();
auto i = _commandByObject.findFirst(object);
const auto end = _commandByObject.end();
for (; i != end && i->first == object; ++i) {
const auto j = CommandNames.find(i->second);
if (j != CommandNames.end()) {
QJsonObject entry;
@ -441,12 +450,9 @@ void Manager::set(const QString &keys, Command command, bool replace) {
_errors.push_back(u"Could not derive key sequence '%1'!"_q.arg(keys));
return;
}
auto shortcut = base::make_unique_q<QShortcut>(
result,
Core::App().activePrimaryWindow()->widget().get(), // #TODO windows
nullptr,
nullptr,
Qt::ApplicationShortcut);
auto shortcut = base::make_unique_q<QAction>();
shortcut->setShortcut(result);
shortcut->setShortcutContext(Qt::ApplicationShortcut);
if (!AutoRepeatCommands.contains(command)) {
shortcut->setAutoRepeat(false);
}
@ -455,20 +461,16 @@ void Manager::set(const QString &keys, Command command, bool replace) {
if (isMediaShortcut || isSupportShortcut) {
shortcut->setEnabled(false);
}
auto id = shortcut->id();
auto object = shortcut.get();
auto i = _shortcuts.find(result);
if (i == end(_shortcuts)) {
i = _shortcuts.emplace(result, std::move(shortcut)).first;
} else if (replace) {
unregister(std::exchange(i->second, std::move(shortcut)));
} else {
id = i->second->id();
object = i->second.get();
}
if (!id) {
_errors.push_back(u"Could not create shortcut '%1'!"_q.arg(keys));
return;
}
_commandByShortcutId.emplace(id, command);
_commandByObject.emplace(object, command);
if (!shortcut && isMediaShortcut) {
_mediaShortcuts.emplace(i->second.get());
}
@ -494,9 +496,9 @@ void Manager::remove(const QString &keys) {
}
}
void Manager::unregister(base::unique_qptr<QShortcut> shortcut) {
void Manager::unregister(base::unique_qptr<QAction> shortcut) {
if (shortcut) {
_commandByShortcutId.erase(shortcut->id());
_commandByObject.erase(shortcut.get());
_mediaShortcuts.erase(shortcut.get());
_supportShortcuts.erase(shortcut.get());
}
@ -560,8 +562,10 @@ const QStringList &Errors() {
return Data.errors();
}
bool HandleEvent(not_null<QShortcutEvent*> event) {
return Launch(Data.lookup(event->shortcutId()));
bool HandleEvent(
not_null<QObject*> object,
not_null<QShortcutEvent*> event) {
return Launch(Data.lookup(object));
}
void ToggleMediaShortcuts(bool toggled) {
@ -576,4 +580,8 @@ void Finish() {
Data.clear();
}
void Listen(not_null<QWidget*> widget) {
Data.listen(widget);
}
} // namespace Shortcuts

View File

@ -100,8 +100,10 @@ rpl::producer<not_null<Request*>> Requests();
void Start();
void Finish();
void Listen(not_null<QWidget*> widget);
bool Launch(Command command);
bool HandleEvent(not_null<QShortcutEvent*> event);
bool HandleEvent(not_null<QObject*> object, not_null<QShortcutEvent*> event);
const QStringList &Errors();

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_account.h" // Account::sessionValue.
#include "core/application.h"
#include "core/sandbox.h"
#include "core/shortcuts.h"
#include "lang/lang_keys.h"
#include "data/data_session.h"
#include "data/data_forum_topic.h"
@ -352,6 +353,8 @@ MainWindow::MainWindow(not_null<Controller*> controller)
updateControlsGeometry();
}, _outdated->lifetime());
}
Shortcuts::Listen(this);
}
Main::Account &MainWindow::account() const {