Skip to content

Commit 15e217f

Browse files
committed
feat: send half of this (idk if it even works tbh)
1 parent fc47e20 commit 15e217f

11 files changed

Lines changed: 199 additions & 10 deletions

File tree

examples/README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,23 @@ doorsctl send next # Send focused window to next desktop
615615
doorsctl send prev|previous # Send focused window to previous desktop
616616
```
617617

618+
### Global Shortcuts (Portal)
619+
620+
Doors implements the XDG Desktop Portal `GlobalShortcuts` interface on
621+
`org.freedesktop.impl.portal.desktop.doors`. Applications can register global
622+
shortcuts via the portal, and Doors notifies them when the bound key is pressed.
623+
624+
```
625+
super + F1
626+
global-shortcut com.appname.app action-name
627+
```
628+
629+
```
630+
doorsctl globalshortcuts
631+
```
632+
633+
List all currently registered global shortcuts across all portal sessions. If none are registered, prints `none`.
634+
618635
#### Other Commands
619636

620637
```

include/config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ typedef enum {
8888
BIND_INTERACTIVE_RESIZE,
8989
BIND_TILING_DRAG,
9090
BIND_EXTERNAL,
91+
BIND_GLOBAL_SHORTCUT,
9192
} bind_action_t;
9293

9394
typedef enum {

include/global_shortcuts.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ void global_shortcuts_init(void);
5858
void global_shortcuts_fini(void);
5959
bool global_shortcuts_handle_key(uint32_t modifiers, uint32_t keycode, const xkb_keysym_t *syms,
6060
int nsyms, uint32_t state, uint32_t time_msec);
61+
void global_shortcuts_send_by_app(const char *app_id, const char *shortcut_id, bool pressed);
62+
void global_shortcuts_list(char *buf, size_t buf_size);

include/ipc_cmd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@ void ipc_cmd_scroller(char **args, int num, int client_fd);
2626
void ipc_cmd_master_stack(char **args, int num, int client_fd);
2727
void ipc_cmd_hotkey(char **args, int num, int client_fd);
2828
void ipc_cmd_scratchpad(char **args, int num, int client_fd);
29+
void ipc_cmd_globalshortcuts(char **args, int num, int client_fd);
2930
void ipc_cmd_bezier(char **args, int num, int client_fd);
3031
void ipc_cmd_spring(char **args, int num, int client_fd);

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ executable(
109109
'src' / 'ipc_cmd' / 'actions.c',
110110
'src' / 'ipc_cmd' / 'config.c',
111111
'src' / 'ipc_cmd' / 'env.c',
112+
'src' / 'ipc_cmd' / 'globalshortcuts.c',
112113
'src' / 'ipc_cmd' / 'desktop.c',
113114
'src' / 'ipc_cmd' / 'dispatch.c',
114115
'src' / 'ipc_cmd' / 'hotkey.c',

src/config.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "config.h"
2+
#include "global_shortcuts.h"
23
#include "keyboard.h"
34
#include "master_stack.h"
45
#include "server.h"
@@ -235,6 +236,9 @@ bind_action_t parse_action(const char *cmd, int *desktop_index, char *submap_nam
235236
return BIND_ENTER_SUBMAP;
236237
}
237238

239+
if (strncmp(cmd, "global-shortcut ", 16) == 0)
240+
return BIND_GLOBAL_SHORTCUT;
241+
238242
if (strncmp(cmd, "doorsctl ", 9) != 0)
239243
return BIND_EXTERNAL;
240244

@@ -698,7 +702,7 @@ static void parse_hotkey_line(const char *hotkey_str, const char *command_str) {
698702
bind_action_t action = parse_action(single_cmd, &desktop_index, submap_name);
699703
wlr_log(WLR_DEBUG, "Parsed action: %d for cmd: '%s' submap: '%s'", action, single_cmd,
700704
submap_name);
701-
if (action != BIND_EXTERNAL)
705+
if (action != BIND_EXTERNAL && action != BIND_GLOBAL_SHORTCUT)
702706
add_keybind(modifiers, keysym, keycode, use_keycode, action, desktop_index, NULL,
703707
submap_name[0] ? submap_name : NULL);
704708
else
@@ -1253,6 +1257,22 @@ void execute_bind(bind_t b) {
12531257
case BIND_INTERACTIVE_RESIZE:
12541258
case BIND_TILING_DRAG:
12551259
break;
1260+
case BIND_GLOBAL_SHORTCUT:
1261+
if (b.external_cmd[0] != '\0') {
1262+
char app_id[256], shortcut_id[256];
1263+
const char *args = b.external_cmd + 16;
1264+
const char *space = strchr(args, ' ');
1265+
if (space) {
1266+
size_t app_len = (size_t)(space - args);
1267+
if (app_len >= sizeof(app_id))
1268+
app_len = sizeof(app_id) - 1;
1269+
memcpy(app_id, args, app_len);
1270+
app_id[app_len] = '\0';
1271+
snprintf(shortcut_id, sizeof(shortcut_id), "%s", space + 1);
1272+
global_shortcuts_send_by_app(app_id, shortcut_id, true);
1273+
}
1274+
}
1275+
break;
12561276
}
12571277
}
12581278

@@ -1466,7 +1486,8 @@ const char *bind_action_name(bind_action_t action) {
14661486
"interactive_move",
14671487
"interactive_resize",
14681488
"tiling_drag",
1469-
"external"
1489+
"external",
1490+
"portal_shortcut"
14701491
};
14711492
if (action >= 0 && action < (int)(sizeof(names) / sizeof(names[0])))
14721493
return names[action];

src/global_shortcuts.c

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <string.h>
77
#include <strings.h>
88
#include <systemd/sd-bus.h>
9+
#include <time.h>
910
#include <wayland-server-core.h>
1011
#include <wlr/types/wlr_keyboard.h>
1112
#include <wlr/util/log.h>
@@ -604,8 +605,7 @@ void global_shortcuts_init(void) {
604605

605606
r = sd_bus_request_name(gs.bus, GS_BUS_NAME, 0);
606607
if (r < 0) {
607-
wlr_log(WLR_ERROR, "failed to request bus name '%s': %s", GS_BUS_NAME,
608-
strerror(-r));
608+
wlr_log(WLR_ERROR, "failed to request bus name '%s': %s", GS_BUS_NAME, strerror(-r));
609609
sd_bus_unref(gs.bus);
610610
gs.bus = NULL;
611611
return;
@@ -708,6 +708,65 @@ bool global_shortcuts_handle_key(uint32_t modifiers, uint32_t keycode, const xkb
708708
return false;
709709
}
710710

711+
void global_shortcuts_send_by_app(const char *app_id, const char *shortcut_id, bool pressed) {
712+
if (!gs.initialized || !gs.bus || !app_id || !shortcut_id)
713+
return;
714+
715+
struct timespec tp;
716+
clock_gettime(CLOCK_MONOTONIC, &tp);
717+
uint64_t timestamp = (uint64_t)tp.tv_sec * 1000 + (uint64_t)tp.tv_nsec / 1000000;
718+
719+
gs_session_t *sess;
720+
wl_list_for_each(sess, &gs.sessions, link) {
721+
if (sess->destroyed)
722+
continue;
723+
if (strcmp(sess->app_id, app_id) != 0)
724+
continue;
725+
gs_shortcut_t *sc;
726+
wl_list_for_each(sc, &sess->shortcuts, link) {
727+
if (strcmp(sc->id, shortcut_id) == 0) {
728+
if (pressed)
729+
emit_activated(sess, sc, timestamp);
730+
else
731+
emit_deactivated(sess, sc, timestamp);
732+
return;
733+
}
734+
}
735+
}
736+
}
737+
738+
void global_shortcuts_list(char *buf, size_t buf_size) {
739+
if (!buf || buf_size == 0)
740+
return;
741+
742+
int offset = 0;
743+
744+
if (!gs.initialized || !gs.bus) {
745+
snprintf(buf, buf_size, "not initialized\n");
746+
return;
747+
}
748+
749+
gs_session_t *sess;
750+
wl_list_for_each(sess, &gs.sessions, link) {
751+
if (sess->destroyed)
752+
continue;
753+
gs_shortcut_t *sc;
754+
wl_list_for_each(sc, &sess->shortcuts, link) {
755+
int ret = snprintf(buf + offset, buf_size - offset, "%s:%s\t%s\n",
756+
sess->app_id ? sess->app_id : "?", sc->id ? sc->id : "?",
757+
sc->description ? sc->description : "");
758+
if (ret < 0)
759+
return;
760+
if ((size_t)ret >= buf_size - offset)
761+
return;
762+
offset += ret;
763+
}
764+
}
765+
766+
if (offset == 0)
767+
snprintf(buf, buf_size, "none\n");
768+
}
769+
711770

712771
#else // !HAVE_SYSTEMD
713772

@@ -733,5 +792,16 @@ bool global_shortcuts_handle_key(uint32_t modifiers, uint32_t keycode, const xkb
733792
return false;
734793
}
735794

795+
void global_shortcuts_send_by_app(const char *app_id, const char *shortcut_id, bool pressed) {
796+
(void)app_id;
797+
(void)shortcut_id;
798+
(void)pressed;
799+
}
800+
801+
void global_shortcuts_list(char *buf, size_t buf_size) {
802+
if (buf && buf_size)
803+
snprintf(buf, buf_size, "not available (no systemd)\n");
804+
}
805+
736806

737807
#endif // HAVE_SYSTEMD

src/ipc_cmd/dispatch.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static const cmd_entry_t cmds[] = {
2222
{"equalize", ipc_cmd_equalize},
2323
{"flip", ipc_cmd_flip},
2424
{"focus", ipc_cmd_focus},
25+
{"globalshortcuts", ipc_cmd_globalshortcuts},
2526
{"hotkey", ipc_cmd_hotkey},
2627
{"input", ipc_cmd_input},
2728
{"keyboard_grouping", ipc_cmd_keyboard_grouping},

src/ipc_cmd/globalshortcuts.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "global_shortcuts.h"
2+
#include "ipc.h"
3+
#include "ipc_cmd.h"
4+
5+
void ipc_cmd_globalshortcuts(char **args, int num, int client_fd) {
6+
(void)args;
7+
(void)num;
8+
char buf[DOORS_BUFSIZ];
9+
global_shortcuts_list(buf, sizeof(buf));
10+
send_success(client_fd, buf);
11+
}

src/ipc_cmd/hotkey.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ void ipc_cmd_hotkey(char **args, int num, int client_fd) {
108108
bind_action_t action = parse_action(cmd, &desktop_index, submap_name);
109109

110110
add_keybind(modifiers, keysym, keycode, use_keycode, action, desktop_index,
111-
action == BIND_EXTERNAL ? cmd : NULL, submap_name[0] ? submap_name : NULL);
111+
(action == BIND_EXTERNAL || action == BIND_GLOBAL_SHORTCUT) ? cmd : NULL,
112+
submap_name[0] ? submap_name : NULL);
112113

113114
send_success(client_fd, "hotkey added\n");
114115
}

0 commit comments

Comments
 (0)