mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 14:05:58 +01:00
GlobalShortcuts protocol impl (#1886)
Implements the `hyprland-global-shortcuts-v1` protocol --------- Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
This commit is contained in:
parent
e4e653ada6
commit
046ad79d11
13 changed files with 259 additions and 8 deletions
|
@ -142,6 +142,7 @@ target_link_libraries(Hyprland
|
||||||
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/ext-workspace-unstable-v1-protocol.o
|
||||||
${CMAKE_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1-protocol.o
|
||||||
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/hyprland-toplevel-export-v1-protocol.o
|
||||||
|
${CMAKE_SOURCE_DIR}/hyprland-global-shortcuts-v1-protocol.o
|
||||||
${CMAKE_SOURCE_DIR}/fractional-scale-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/fractional-scale-v1-protocol.o
|
||||||
${CMAKE_SOURCE_DIR}/text-input-unstable-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/text-input-unstable-v1-protocol.o
|
||||||
${CMAKE_SOURCE_DIR}/wlr-screencopy-unstable-v1-protocol.o
|
${CMAKE_SOURCE_DIR}/wlr-screencopy-unstable-v1-protocol.o
|
||||||
|
|
12
Makefile
12
Makefile
|
@ -101,6 +101,16 @@ hyprland-toplevel-export-v1-protocol.c:
|
||||||
|
|
||||||
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
|
hyprland-toplevel-export-v1-protocol.o: hyprland-toplevel-export-v1-protocol.h
|
||||||
|
|
||||||
|
hyprland-global-shortcuts-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) server-header \
|
||||||
|
subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml $@
|
||||||
|
|
||||||
|
hyprland-global-shortcuts-v1-protocol.c:
|
||||||
|
$(WAYLAND_SCANNER) private-code \
|
||||||
|
subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml $@
|
||||||
|
|
||||||
|
hyprland-global-shortcuts-v1-protocol.o: hyprland-global-shortcuts-v1-protocol.h
|
||||||
|
|
||||||
linux-dmabuf-unstable-v1-protocol.h:
|
linux-dmabuf-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) server-header \
|
$(WAYLAND_SCANNER) server-header \
|
||||||
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
$(WAYLAND_PROTOCOLS)/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml $@
|
||||||
|
@ -206,7 +216,7 @@ uninstall:
|
||||||
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
rm -f ${PREFIX}/share/man/man1/Hyprland.1
|
||||||
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
rm -f ${PREFIX}/share/man/man1/hyprctl.1
|
||||||
|
|
||||||
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o wlr-foreign-toplevel-management-unstable-v1-protocol.o fractional-scale-v1-protocol.o text-input-unstable-v1-protocol.o
|
protocols: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o wlr-screencopy-unstable-v1-protocol.o idle-protocol.o ext-workspace-unstable-v1-protocol.o pointer-constraints-unstable-v1-protocol.o tablet-unstable-v2-protocol.o wlr-output-power-management-unstable-v1-protocol.o linux-dmabuf-unstable-v1-protocol.o hyprland-toplevel-export-v1-protocol.o wlr-foreign-toplevel-management-unstable-v1-protocol.o fractional-scale-v1-protocol.o text-input-unstable-v1-protocol.o hyprland-global-shortcuts-v1-protocol.o
|
||||||
|
|
||||||
fixwlr:
|
fixwlr:
|
||||||
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
sed -i -E 's/(soversion = 12)([^032]|$$)/soversion = 12032/g' subprojects/wlroots/meson.build
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1671839510,
|
"lastModified": 1680997116,
|
||||||
"narHash": "sha256-+PY1qqJfmZzzROgcIY4I7AkCwpnC+qBIYk2eFoA9RWc=",
|
"narHash": "sha256-nNyoatiHmTMczrCoHCH2LIRfSF8n9ZPZ1O7WNMxcbR4=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "hyprland-protocols",
|
"repo": "hyprland-protocols",
|
||||||
"rev": "b8f55e02a328c47ed373133c52483bbfa20a1b75",
|
"rev": "d7d403b711b60e8136295b0d4229e89a115e80cc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -43,6 +43,7 @@ commands:
|
||||||
setprop
|
setprop
|
||||||
plugin
|
plugin
|
||||||
notify
|
notify
|
||||||
|
globalshortcuts
|
||||||
|
|
||||||
flags:
|
flags:
|
||||||
-j -> output in JSON
|
-j -> output in JSON
|
||||||
|
@ -345,6 +346,8 @@ int main(int argc, char** argv) {
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/animations"))
|
else if (fullRequest.contains("/animations"))
|
||||||
request(fullRequest);
|
request(fullRequest);
|
||||||
|
else if (fullRequest.contains("/globalshortcuts"))
|
||||||
|
request(fullRequest);
|
||||||
else if (fullRequest.contains("/switchxkblayout"))
|
else if (fullRequest.contains("/switchxkblayout"))
|
||||||
request(fullRequest, 2);
|
request(fullRequest, 2);
|
||||||
else if (fullRequest.contains("/seterror"))
|
else if (fullRequest.contains("/seterror"))
|
||||||
|
|
|
@ -31,7 +31,8 @@ protocols = [
|
||||||
['pointer-constraints-unstable-v1.xml'],
|
['pointer-constraints-unstable-v1.xml'],
|
||||||
['tablet-unstable-v2.xml'],
|
['tablet-unstable-v2.xml'],
|
||||||
['idle.xml'],
|
['idle.xml'],
|
||||||
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml']
|
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
|
||||||
|
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
|
||||||
]
|
]
|
||||||
wl_protos_src = []
|
wl_protos_src = []
|
||||||
wl_protos_headers = []
|
wl_protos_headers = []
|
||||||
|
|
|
@ -536,6 +536,29 @@ std::string animationsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string globalShortcutsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
|
std::string ret = "";
|
||||||
|
const auto SHORTCUTS = g_pProtocolManager->m_pGlobalShortcutsProtocolManager->getAllShortcuts();
|
||||||
|
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||||
|
for (auto& sh : SHORTCUTS)
|
||||||
|
ret += getFormat("%s:%s -> %s\n", sh.appid.c_str(), sh.id.c_str(), sh.description.c_str());
|
||||||
|
} else {
|
||||||
|
ret += "[";
|
||||||
|
for (auto& sh : SHORTCUTS) {
|
||||||
|
ret += getFormat(R"#(
|
||||||
|
{
|
||||||
|
"name": "%s",
|
||||||
|
"description": "%s"
|
||||||
|
},)#",
|
||||||
|
escapeJSONStrings(sh.appid + ":" + sh.id).c_str(), escapeJSONStrings(sh.description).c_str());
|
||||||
|
}
|
||||||
|
ret.pop_back();
|
||||||
|
ret += "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
std::string bindsRequest(HyprCtl::eHyprCtlOutputFormat format) {
|
||||||
std::string ret = "";
|
std::string ret = "";
|
||||||
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
if (format == HyprCtl::eHyprCtlOutputFormat::FORMAT_NORMAL) {
|
||||||
|
@ -1228,6 +1251,8 @@ std::string getReply(std::string request) {
|
||||||
return cursorPosRequest(format);
|
return cursorPosRequest(format);
|
||||||
else if (request == "binds")
|
else if (request == "binds")
|
||||||
return bindsRequest(format);
|
return bindsRequest(format);
|
||||||
|
else if (request == "globalshortcuts")
|
||||||
|
return globalShortcutsRequest(format);
|
||||||
else if (request == "animations")
|
else if (request == "animations")
|
||||||
return animationsRequest(format);
|
return animationsRequest(format);
|
||||||
else if (request.find("plugin") == 0)
|
else if (request.find("plugin") == 0)
|
||||||
|
|
|
@ -63,6 +63,7 @@ CKeybindManager::CKeybindManager() {
|
||||||
m_mDispatchers["lockgroups"] = lockGroups;
|
m_mDispatchers["lockgroups"] = lockGroups;
|
||||||
m_mDispatchers["moveintogroup"] = moveIntoGroup;
|
m_mDispatchers["moveintogroup"] = moveIntoGroup;
|
||||||
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
|
m_mDispatchers["moveoutofgroup"] = moveOutOfGroup;
|
||||||
|
m_mDispatchers["global"] = global;
|
||||||
|
|
||||||
m_tScrollTimer.reset();
|
m_tScrollTimer.reset();
|
||||||
}
|
}
|
||||||
|
@ -352,7 +353,7 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
|
||||||
|
|
||||||
for (auto& k : m_lKeybinds) {
|
for (auto& k : m_lKeybinds) {
|
||||||
if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap ||
|
if (modmask != k.modmask || (g_pCompositor->m_sSeat.exclusiveClient && !k.locked) || k.submap != m_szCurrentSelectedSubmap ||
|
||||||
(!pressed && !k.release && k.handler != "pass" && k.handler != "mouse") || k.shadowed)
|
(!pressed && !k.release && k.handler != "pass" && k.handler != "mouse" && k.handler != "global") || k.shadowed)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!key.empty()) {
|
if (!key.empty()) {
|
||||||
|
@ -425,7 +426,10 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int&
|
||||||
|
|
||||||
for (auto& k : m_lKeybinds) {
|
for (auto& k : m_lKeybinds) {
|
||||||
|
|
||||||
bool shadow = false;
|
bool shadow = false;
|
||||||
|
|
||||||
|
if (k.handler == "global")
|
||||||
|
continue; // can't be shadowed
|
||||||
|
|
||||||
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
|
const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
|
||||||
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
|
const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY);
|
||||||
|
@ -2139,3 +2143,16 @@ void CKeybindManager::moveOutOfGroup(std::string args) {
|
||||||
|
|
||||||
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
g_pKeybindManager->m_bGroupsLocked = GROUPSLOCKEDPREV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CKeybindManager::global(std::string args) {
|
||||||
|
const auto APPID = args.substr(0, args.find_first_of(':'));
|
||||||
|
const auto NAME = args.substr(args.find_first_of(':') + 1);
|
||||||
|
|
||||||
|
if (APPID.empty() || NAME.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!g_pProtocolManager->m_pGlobalShortcutsProtocolManager->globalShortcutExists(APPID, NAME))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->sendGlobalShortcutEvent(APPID, NAME, g_pKeybindManager->m_iPassPressed);
|
||||||
|
}
|
|
@ -139,6 +139,7 @@ class CKeybindManager {
|
||||||
static void lockGroups(std::string);
|
static void lockGroups(std::string);
|
||||||
static void moveIntoGroup(std::string);
|
static void moveIntoGroup(std::string);
|
||||||
static void moveOutOfGroup(std::string);
|
static void moveOutOfGroup(std::string);
|
||||||
|
static void global(std::string);
|
||||||
|
|
||||||
friend class CCompositor;
|
friend class CCompositor;
|
||||||
friend class CInputManager;
|
friend class CInputManager;
|
||||||
|
|
|
@ -4,5 +4,6 @@ CProtocolManager::CProtocolManager() {
|
||||||
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
m_pToplevelExportProtocolManager = std::make_unique<CToplevelExportProtocolManager>();
|
||||||
m_pFractionalScaleProtocolManager = std::make_unique<CFractionalScaleProtocolManager>();
|
m_pFractionalScaleProtocolManager = std::make_unique<CFractionalScaleProtocolManager>();
|
||||||
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
|
m_pTextInputV1ProtocolManager = std::make_unique<CTextInputV1ProtocolManager>();
|
||||||
|
m_pGlobalShortcutsProtocolManager = std::make_unique<CGlobalShortcutsProtocolManager>();
|
||||||
m_pScreencopyProtocolManager = std::make_unique<CScreencopyProtocolManager>();
|
m_pScreencopyProtocolManager = std::make_unique<CScreencopyProtocolManager>();
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../protocols/ToplevelExport.hpp"
|
#include "../protocols/ToplevelExport.hpp"
|
||||||
#include "../protocols/FractionalScale.hpp"
|
#include "../protocols/FractionalScale.hpp"
|
||||||
#include "../protocols/TextInputV1.hpp"
|
#include "../protocols/TextInputV1.hpp"
|
||||||
|
#include "../protocols/GlobalShortcuts.hpp"
|
||||||
#include "../protocols/Screencopy.hpp"
|
#include "../protocols/Screencopy.hpp"
|
||||||
|
|
||||||
class CProtocolManager {
|
class CProtocolManager {
|
||||||
|
@ -13,6 +14,7 @@ class CProtocolManager {
|
||||||
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
std::unique_ptr<CToplevelExportProtocolManager> m_pToplevelExportProtocolManager;
|
||||||
std::unique_ptr<CFractionalScaleProtocolManager> m_pFractionalScaleProtocolManager;
|
std::unique_ptr<CFractionalScaleProtocolManager> m_pFractionalScaleProtocolManager;
|
||||||
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
|
std::unique_ptr<CTextInputV1ProtocolManager> m_pTextInputV1ProtocolManager;
|
||||||
|
std::unique_ptr<CGlobalShortcutsProtocolManager> m_pGlobalShortcutsProtocolManager;
|
||||||
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
|
std::unique_ptr<CScreencopyProtocolManager> m_pScreencopyProtocolManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
151
src/protocols/GlobalShortcuts.cpp
Normal file
151
src/protocols/GlobalShortcuts.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
#include "GlobalShortcuts.hpp"
|
||||||
|
#include "../Compositor.hpp"
|
||||||
|
|
||||||
|
#define GLOBAL_SHORTCUTS_VERSION 1
|
||||||
|
|
||||||
|
static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||||
|
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->bindManager(client, data, version, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDisplayDestroy(struct wl_listener* listener, void* data) {
|
||||||
|
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->displayDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGlobalShortcutsProtocolManager::displayDestroy() {
|
||||||
|
wl_global_destroy(m_pGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGlobalShortcutsProtocolManager::CGlobalShortcutsProtocolManager() {
|
||||||
|
m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &hyprland_global_shortcuts_manager_v1_interface, GLOBAL_SHORTCUTS_VERSION, this, bindManagerInt);
|
||||||
|
|
||||||
|
if (!m_pGlobal) {
|
||||||
|
Debug::log(ERR, "GlobalShortcutsManager could not start!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_liDisplayDestroy.notify = handleDisplayDestroy;
|
||||||
|
wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy);
|
||||||
|
|
||||||
|
Debug::log(LOG, "GlobalShortcutsManager started successfully!");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleRegisterShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
|
||||||
|
const char* trigger_description) {
|
||||||
|
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->registerShortcut(client, resource, shortcut, id, app_id, description, trigger_description);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleDestroy(wl_client* client, wl_resource* resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct hyprland_global_shortcuts_manager_v1_interface globalShortcutsManagerImpl = {
|
||||||
|
.register_shortcut = handleRegisterShortcut,
|
||||||
|
.destroy = handleDestroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct hyprland_global_shortcut_v1_interface shortcutImpl = {
|
||||||
|
.destroy = handleDestroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
void CGlobalShortcutsProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||||
|
const auto RESOURCE = wl_resource_create(client, &hyprland_global_shortcuts_manager_v1_interface, version, id);
|
||||||
|
wl_resource_set_implementation(RESOURCE, &globalShortcutsManagerImpl, this, nullptr);
|
||||||
|
|
||||||
|
Debug::log(LOG, "GlobalShortcutsManager bound successfully!");
|
||||||
|
|
||||||
|
m_vClients.emplace_back(std::make_unique<SShortcutClient>(client));
|
||||||
|
}
|
||||||
|
|
||||||
|
SShortcutClient* CGlobalShortcutsProtocolManager::clientFromWlClient(wl_client* client) {
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
if (c->client == client) {
|
||||||
|
return c.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onShortcutDestroy(wl_resource* pResource) {
|
||||||
|
g_pProtocolManager->m_pGlobalShortcutsProtocolManager->destroyShortcut(pResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGlobalShortcutsProtocolManager::registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
|
||||||
|
const char* trigger_description) {
|
||||||
|
const auto PCLIENT = clientFromWlClient(client);
|
||||||
|
|
||||||
|
if (!PCLIENT) {
|
||||||
|
Debug::log(ERR, "Error at global shortcuts: no client in register?");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
for (auto& sh : c->shortcuts) {
|
||||||
|
if (sh->appid == app_id && sh->id == id) {
|
||||||
|
wl_resource_post_error(resource, HYPRLAND_GLOBAL_SHORTCUTS_MANAGER_V1_ERROR_ALREADY_TAKEN, "Combination is taken");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto PSHORTCUT = PCLIENT->shortcuts.emplace_back(std::make_unique<SShortcut>()).get();
|
||||||
|
PSHORTCUT->id = id;
|
||||||
|
PSHORTCUT->description = description;
|
||||||
|
PSHORTCUT->appid = app_id;
|
||||||
|
PSHORTCUT->shortcut = shortcut;
|
||||||
|
|
||||||
|
PSHORTCUT->resource = wl_resource_create(client, &hyprland_global_shortcut_v1_interface, 1, shortcut);
|
||||||
|
if (!PSHORTCUT->resource) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
std::erase_if(PCLIENT->shortcuts, [&](const auto& other) { return other.get() == PSHORTCUT; });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_set_implementation(PSHORTCUT->resource, &shortcutImpl, this, &onShortcutDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGlobalShortcutsProtocolManager::globalShortcutExists(std::string appid, std::string trigger) {
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
for (auto& sh : c->shortcuts) {
|
||||||
|
if (sh->appid == appid && sh->id == trigger) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGlobalShortcutsProtocolManager::sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed) {
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
for (auto& sh : c->shortcuts) {
|
||||||
|
if (sh->appid == appid && sh->id == trigger) {
|
||||||
|
timespec now;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
uint32_t tvSecHi = (sizeof(now.tv_sec) > 4) ? now.tv_sec >> 32 : 0;
|
||||||
|
uint32_t tvSecLo = now.tv_sec & 0xFFFFFFFF;
|
||||||
|
if (pressed)
|
||||||
|
hyprland_global_shortcut_v1_send_pressed(sh->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
||||||
|
else
|
||||||
|
hyprland_global_shortcut_v1_send_released(sh->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SShortcut> CGlobalShortcutsProtocolManager::getAllShortcuts() {
|
||||||
|
std::vector<SShortcut> copy;
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
for (auto& sh : c->shortcuts) {
|
||||||
|
copy.push_back(*sh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGlobalShortcutsProtocolManager::destroyShortcut(wl_resource* resource) {
|
||||||
|
for (auto& c : m_vClients) {
|
||||||
|
std::erase_if(c->shortcuts, [&](const auto& other) { return other->resource == resource; });
|
||||||
|
}
|
||||||
|
}
|
39
src/protocols/GlobalShortcuts.hpp
Normal file
39
src/protocols/GlobalShortcuts.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../defines.hpp"
|
||||||
|
#include "hyprland-global-shortcuts-v1-protocol.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct SShortcut {
|
||||||
|
wl_resource* resource;
|
||||||
|
std::string id, description, appid;
|
||||||
|
uint32_t shortcut = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SShortcutClient {
|
||||||
|
wl_client* client = nullptr;
|
||||||
|
std::vector<std::unique_ptr<SShortcut>> shortcuts;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CGlobalShortcutsProtocolManager {
|
||||||
|
public:
|
||||||
|
CGlobalShortcutsProtocolManager();
|
||||||
|
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
|
void displayDestroy();
|
||||||
|
|
||||||
|
void registerShortcut(wl_client* client, wl_resource* resource, uint32_t shortcut, const char* id, const char* app_id, const char* description,
|
||||||
|
const char* trigger_description);
|
||||||
|
void destroyShortcut(wl_resource* resource);
|
||||||
|
|
||||||
|
bool globalShortcutExists(std::string appid, std::string trigger);
|
||||||
|
void sendGlobalShortcutEvent(std::string appid, std::string trigger, bool pressed);
|
||||||
|
|
||||||
|
std::vector<SShortcut> getAllShortcuts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<SShortcutClient>> m_vClients;
|
||||||
|
|
||||||
|
SShortcutClient* clientFromWlClient(wl_client* client);
|
||||||
|
|
||||||
|
wl_global* m_pGlobal = nullptr;
|
||||||
|
wl_listener m_liDisplayDestroy;
|
||||||
|
};
|
|
@ -1 +1 @@
|
||||||
Subproject commit 301733ae466b229066ba15a53e6d8b91c5dcef5b
|
Subproject commit d7d403b711b60e8136295b0d4229e89a115e80cc
|
Loading…
Reference in a new issue