mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-06 00:35:58 +01:00
[WIP] Global Shortcuts impl (#35)
Implements the `GlobalShortcuts` portal via `hyprland-global-shortcuts-v1` --------- Co-authored-by: Mihai Fufezan <fufexan@protonmail.com>
This commit is contained in:
parent
803c00db11
commit
510257c0e9
10 changed files with 924 additions and 403 deletions
12
flake.lock
12
flake.lock
|
@ -7,11 +7,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1671839510,
|
||||
"narHash": "sha256-+PY1qqJfmZzzROgcIY4I7AkCwpnC+qBIYk2eFoA9RWc=",
|
||||
"lastModified": 1680997116,
|
||||
"narHash": "sha256-nNyoatiHmTMczrCoHCH2LIRfSF8n9ZPZ1O7WNMxcbR4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "b8f55e02a328c47ed373133c52483bbfa20a1b75",
|
||||
"rev": "d7d403b711b60e8136295b0d4229e89a115e80cc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -22,11 +22,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1669969257,
|
||||
"narHash": "sha256-mOS13sK3v+kfgP+1Mh56ohiG8uVhLHAo7m/q9kqAehc=",
|
||||
"lastModified": 1680945546,
|
||||
"narHash": "sha256-8FuaH5t/aVi/pR1XxnF0qi4WwMYC+YxlfdsA0V+TEuQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b72b8b94cf0c012b0252a9100a636cad69696666",
|
||||
"rev": "d9f759f2ea8d265d974a6e1259bd510ac5844c5d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[portal]
|
||||
DBusName=org.freedesktop.impl.portal.desktop.hyprland
|
||||
Interfaces=org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.ScreenCast;
|
||||
Interfaces=org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.ScreenCast;org.freedesktop.impl.portal.GlobalShortcuts;
|
||||
UseIn=wlroots;Hyprland;sway;Wayfire;river;
|
||||
|
|
31
include/global_shortcuts.h
Normal file
31
include/global_shortcuts.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "protocols/hyprland-global-shortcuts-v1-client-protocol.h"
|
||||
|
||||
struct xdpw_state;
|
||||
struct xdpw_session;
|
||||
|
||||
struct globalShortcut {
|
||||
char* name;
|
||||
char* description;
|
||||
struct wl_list link;
|
||||
struct hyprland_global_shortcut_v1* hlShortcut;
|
||||
bool bound;
|
||||
};
|
||||
|
||||
struct globalShortcutsClient {
|
||||
struct xdpw_session* session;
|
||||
struct wl_list shortcuts; // struct globalShortcut*
|
||||
struct wl_list link;
|
||||
char* parent_window;
|
||||
bool sentShortcuts;
|
||||
};
|
||||
|
||||
struct globalShortcutsInstance {
|
||||
struct hyprland_global_shortcuts_manager_v1* manager;
|
||||
struct wl_list shortcutClients; // struct globalShortcutsClient*
|
||||
};
|
||||
|
||||
void initShortcutsInstance(struct xdpw_state* state, struct globalShortcutsInstance* instance);
|
|
@ -10,52 +10,51 @@
|
|||
#include <basu/sd-bus.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "global_shortcuts.h"
|
||||
#include "screencast_common.h"
|
||||
#include "screenshot_common.h"
|
||||
#include "config.h"
|
||||
|
||||
struct xdpw_state {
|
||||
struct wl_list xdpw_sessions;
|
||||
sd_bus *bus;
|
||||
struct wl_display *wl_display;
|
||||
struct pw_loop *pw_loop;
|
||||
struct xdpw_screencast_context screencast;
|
||||
uint32_t screencast_source_types; // bitfield of enum source_types
|
||||
uint32_t screencast_cursor_modes; // bitfield of enum cursor_modes
|
||||
uint32_t screencast_version;
|
||||
uint32_t screenshot_version;
|
||||
struct xdpw_config *config;
|
||||
int timer_poll_fd;
|
||||
struct wl_list timers;
|
||||
struct xdpw_timer *next_timer;
|
||||
struct wl_list xdpw_sessions;
|
||||
sd_bus *bus;
|
||||
struct wl_display *wl_display;
|
||||
struct pw_loop *pw_loop;
|
||||
struct xdpw_screencast_context screencast;
|
||||
uint32_t screencast_source_types; // bitfield of enum source_types
|
||||
uint32_t screencast_cursor_modes; // bitfield of enum cursor_modes
|
||||
uint32_t screencast_version;
|
||||
uint32_t screenshot_version;
|
||||
struct xdpw_config *config;
|
||||
int timer_poll_fd;
|
||||
struct wl_list timers;
|
||||
struct xdpw_timer *next_timer;
|
||||
struct globalShortcutsInstance shortcutsInstance;
|
||||
};
|
||||
|
||||
struct xdpw_request {
|
||||
sd_bus_slot *slot;
|
||||
sd_bus_slot *slot;
|
||||
};
|
||||
|
||||
struct xdpw_session {
|
||||
struct wl_list link;
|
||||
sd_bus_slot *slot;
|
||||
char *session_handle;
|
||||
struct xdpw_screencast_instance *screencast_instance;
|
||||
struct wl_list link;
|
||||
sd_bus_slot *slot;
|
||||
char *session_handle;
|
||||
char *app_id;
|
||||
struct xdpw_screencast_instance *screencast_instance;
|
||||
};
|
||||
|
||||
typedef void (*xdpw_event_loop_timer_func_t)(void *data);
|
||||
|
||||
struct xdpw_timer {
|
||||
struct xdpw_state *state;
|
||||
xdpw_event_loop_timer_func_t func;
|
||||
void *user_data;
|
||||
struct timespec at;
|
||||
struct wl_list link; // xdpw_state::timers
|
||||
struct xdpw_state *state;
|
||||
xdpw_event_loop_timer_func_t func;
|
||||
void *user_data;
|
||||
struct timespec at;
|
||||
struct wl_list link; // xdpw_state::timers
|
||||
};
|
||||
|
||||
enum {
|
||||
PORTAL_RESPONSE_SUCCESS = 0,
|
||||
PORTAL_RESPONSE_CANCELLED = 1,
|
||||
PORTAL_RESPONSE_ENDED = 2
|
||||
};
|
||||
enum { PORTAL_RESPONSE_SUCCESS = 0, PORTAL_RESPONSE_CANCELLED = 1, PORTAL_RESPONSE_ENDED = 2 };
|
||||
|
||||
int xdpw_screenshot_init(struct xdpw_state *state);
|
||||
int xdpw_screencast_init(struct xdpw_state *state);
|
||||
|
@ -66,8 +65,7 @@ void xdpw_request_destroy(struct xdpw_request *req);
|
|||
struct xdpw_session *xdpw_session_create(struct xdpw_state *state, sd_bus *bus, char *object_path);
|
||||
void xdpw_session_destroy(struct xdpw_session *req);
|
||||
|
||||
struct xdpw_timer *xdpw_add_timer(struct xdpw_state *state,
|
||||
uint64_t delay_ns, xdpw_event_loop_timer_func_t func, void *data);
|
||||
struct xdpw_timer *xdpw_add_timer(struct xdpw_state *state, uint64_t delay_ns, xdpw_event_loop_timer_func_t func, void *data);
|
||||
|
||||
void xdpw_destroy_timer(struct xdpw_timer *timer);
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ xdpw_files = files([
|
|||
'src/screencast/wlr_screencast.c',
|
||||
'src/screencast/pipewire_screencast.c',
|
||||
'src/screencast/fps_limit.c',
|
||||
'src/globalshortcuts/global_shortcuts.c'
|
||||
])
|
||||
|
||||
executable(
|
||||
|
|
|
@ -15,6 +15,7 @@ client_protocols = [
|
|||
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
|
||||
hl_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
|
||||
hl_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||
]
|
||||
|
|
464
src/core/main.c
464
src/core/main.c
|
@ -1,288 +1,290 @@
|
|||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <getopt.h>
|
||||
#include <poll.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <poll.h>
|
||||
#include <spa/utils/result.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "xdpw.h"
|
||||
#include "logger.h"
|
||||
#include "xdpw.h"
|
||||
|
||||
enum event_loop_fd {
|
||||
EVENT_LOOP_DBUS,
|
||||
EVENT_LOOP_WAYLAND,
|
||||
EVENT_LOOP_PIPEWIRE,
|
||||
EVENT_LOOP_TIMER,
|
||||
EVENT_LOOP_DBUS,
|
||||
EVENT_LOOP_WAYLAND,
|
||||
EVENT_LOOP_PIPEWIRE,
|
||||
EVENT_LOOP_TIMER,
|
||||
};
|
||||
|
||||
static const char service_name[] = "org.freedesktop.impl.portal.desktop.hyprland";
|
||||
|
||||
static int xdpw_usage(FILE *stream, int rc) {
|
||||
static const char *usage =
|
||||
"Usage: xdg-desktop-portal-hyprland [options]\n"
|
||||
"\n"
|
||||
" -l, --loglevel=<loglevel> Select log level (default is ERROR).\n"
|
||||
" QUIET, ERROR, WARN, INFO, DEBUG, TRACE\n"
|
||||
" -c, --config=<config file> Select config file.\n"
|
||||
" (default is $XDG_CONFIG_HOME/xdg-desktop-portal-hyprland/config)\n"
|
||||
" -r, --replace Replace a running instance.\n"
|
||||
" -h, --help Get help (this text).\n"
|
||||
"\n";
|
||||
static const char *usage =
|
||||
"Usage: xdg-desktop-portal-hyprland [options]\n"
|
||||
"\n"
|
||||
" -l, --loglevel=<loglevel> Select log level (default is ERROR).\n"
|
||||
" QUIET, ERROR, WARN, INFO, DEBUG, TRACE\n"
|
||||
" -c, --config=<config file> Select config file.\n"
|
||||
" (default is $XDG_CONFIG_HOME/xdg-desktop-portal-hyprland/config)\n"
|
||||
" -r, --replace Replace a running instance.\n"
|
||||
" -h, --help Get help (this text).\n"
|
||||
"\n";
|
||||
|
||||
fprintf(stream, "%s", usage);
|
||||
return rc;
|
||||
fprintf(stream, "%s", usage);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int handle_name_lost(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||
logprint(INFO, "dbus: lost name, closing connection");
|
||||
sd_bus_close(sd_bus_message_get_bus(m));
|
||||
return 1;
|
||||
logprint(INFO, "dbus: lost name, closing connection");
|
||||
sd_bus_close(sd_bus_message_get_bus(m));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct xdpw_config config = {0};
|
||||
char *configfile = NULL;
|
||||
enum LOGLEVEL loglevel = DEFAULT_LOGLEVEL;
|
||||
bool replace = false;
|
||||
struct xdpw_config config = {0};
|
||||
char *configfile = NULL;
|
||||
enum LOGLEVEL loglevel = DEFAULT_LOGLEVEL;
|
||||
bool replace = false;
|
||||
|
||||
static const char *shortopts = "l:o:c:f:rh";
|
||||
static const struct option longopts[] = {
|
||||
{ "loglevel", required_argument, NULL, 'l' },
|
||||
{ "config", required_argument, NULL, 'c' },
|
||||
{ "replace", no_argument, NULL, 'r' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
static const char *shortopts = "l:o:c:f:rh";
|
||||
static const struct option longopts[] = {{"loglevel", required_argument, NULL, 'l'},
|
||||
{"config", required_argument, NULL, 'c'},
|
||||
{"replace", no_argument, NULL, 'r'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}};
|
||||
|
||||
while (1) {
|
||||
int c = getopt_long(argc, argv, shortopts, longopts, NULL);
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
int c = getopt_long(argc, argv, shortopts, longopts, NULL);
|
||||
if (c < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (c) {
|
||||
case 'l':
|
||||
loglevel = get_loglevel(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
configfile = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
replace = true;
|
||||
break;
|
||||
case 'h':
|
||||
return xdpw_usage(stdout, EXIT_SUCCESS);
|
||||
default:
|
||||
return xdpw_usage(stderr, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
switch (c) {
|
||||
case 'l':
|
||||
loglevel = get_loglevel(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
configfile = strdup(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
replace = true;
|
||||
break;
|
||||
case 'h':
|
||||
return xdpw_usage(stdout, EXIT_SUCCESS);
|
||||
default:
|
||||
return xdpw_usage(stderr, EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
init_logger(stderr, loglevel);
|
||||
init_config(&configfile, &config);
|
||||
print_config(DEBUG, &config);
|
||||
init_logger(stderr, loglevel);
|
||||
init_config(&configfile, &config);
|
||||
print_config(DEBUG, &config);
|
||||
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
sd_bus *bus = NULL;
|
||||
ret = sd_bus_open_user(&bus);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to connect to user bus: %s", strerror(-ret));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "dbus: connected");
|
||||
sd_bus *bus = NULL;
|
||||
ret = sd_bus_open_user(&bus);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to connect to user bus: %s", strerror(-ret));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "dbus: connected");
|
||||
|
||||
struct wl_display *wl_display = wl_display_connect(NULL);
|
||||
if (!wl_display) {
|
||||
logprint(ERROR, "wayland: failed to connect to display");
|
||||
sd_bus_unref(bus);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "wlroots: wl_display connected");
|
||||
struct wl_display *wl_display = wl_display_connect(NULL);
|
||||
if (!wl_display) {
|
||||
logprint(ERROR, "wayland: failed to connect to display");
|
||||
sd_bus_unref(bus);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "wlroots: wl_display connected");
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
struct pw_loop *pw_loop = pw_loop_new(NULL);
|
||||
if (!pw_loop) {
|
||||
logprint(ERROR, "pipewire: failed to create loop");
|
||||
wl_display_disconnect(wl_display);
|
||||
sd_bus_unref(bus);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "pipewire: pw_loop created");
|
||||
pw_init(NULL, NULL);
|
||||
struct pw_loop *pw_loop = pw_loop_new(NULL);
|
||||
if (!pw_loop) {
|
||||
logprint(ERROR, "pipewire: failed to create loop");
|
||||
wl_display_disconnect(wl_display);
|
||||
sd_bus_unref(bus);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
logprint(DEBUG, "pipewire: pw_loop created");
|
||||
|
||||
struct xdpw_state state = {
|
||||
.bus = bus,
|
||||
.wl_display = wl_display,
|
||||
.pw_loop = pw_loop,
|
||||
.screencast_source_types = MONITOR,
|
||||
.screencast_cursor_modes = HIDDEN | EMBEDDED | METADATA,
|
||||
.screencast_version = XDP_CAST_PROTO_VER,
|
||||
.screenshot_version = XDP_SHOT_PROTO_VER,
|
||||
.config = &config,
|
||||
};
|
||||
struct xdpw_state state = {
|
||||
.bus = bus,
|
||||
.wl_display = wl_display,
|
||||
.pw_loop = pw_loop,
|
||||
.screencast_source_types = MONITOR,
|
||||
.screencast_cursor_modes = HIDDEN | EMBEDDED,
|
||||
.screencast_version = XDP_CAST_PROTO_VER,
|
||||
.screenshot_version = XDP_SHOT_PROTO_VER,
|
||||
.config = &config,
|
||||
};
|
||||
|
||||
wl_list_init(&state.xdpw_sessions);
|
||||
wl_list_init(&state.xdpw_sessions);
|
||||
|
||||
ret = xdpw_screenshot_init(&state);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "xdpw: failed to initialize screenshot");
|
||||
goto error;
|
||||
}
|
||||
initShortcutsInstance(&state, &state.shortcutsInstance);
|
||||
|
||||
ret = xdpw_screencast_init(&state);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "xdpw: failed to initialize screencast");
|
||||
goto error;
|
||||
}
|
||||
ret = xdpw_screenshot_init(&state);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "xdpw: failed to initialize screenshot");
|
||||
goto error;
|
||||
}
|
||||
|
||||
uint64_t flags = SD_BUS_NAME_ALLOW_REPLACEMENT;
|
||||
if (replace) {
|
||||
flags |= SD_BUS_NAME_REPLACE_EXISTING;
|
||||
}
|
||||
ret = xdpw_screencast_init(&state);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "xdpw: failed to initialize screencast");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = sd_bus_request_name(bus, service_name, flags);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to acquire service name: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
uint64_t flags = SD_BUS_NAME_ALLOW_REPLACEMENT;
|
||||
if (replace) {
|
||||
flags |= SD_BUS_NAME_REPLACE_EXISTING;
|
||||
}
|
||||
|
||||
const char *unique_name;
|
||||
ret = sd_bus_get_unique_name(bus, &unique_name);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to get unique bus name: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
ret = sd_bus_request_name(bus, service_name, flags);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to acquire service name: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
static char match[1024];
|
||||
snprintf(match, sizeof(match), "sender='org.freedesktop.DBus',"
|
||||
"type='signal',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"arg0='%s',"
|
||||
"arg1='%s'",
|
||||
service_name, unique_name);
|
||||
const char *unique_name;
|
||||
ret = sd_bus_get_unique_name(bus, &unique_name);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to get unique bus name: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
sd_bus_slot *slot;
|
||||
ret = sd_bus_add_match(bus, &slot, match, handle_name_lost, NULL);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to add NameOwnerChanged signal match: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
static char match[1024];
|
||||
snprintf(match, sizeof(match),
|
||||
"sender='org.freedesktop.DBus',"
|
||||
"type='signal',"
|
||||
"interface='org.freedesktop.DBus',"
|
||||
"member='NameOwnerChanged',"
|
||||
"path='/org/freedesktop/DBus',"
|
||||
"arg0='%s',"
|
||||
"arg1='%s'",
|
||||
service_name, unique_name);
|
||||
|
||||
wl_list_init(&state.timers);
|
||||
sd_bus_slot *slot;
|
||||
ret = sd_bus_add_match(bus, &slot, match, handle_name_lost, NULL);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "dbus: failed to add NameOwnerChanged signal match: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
struct pollfd pollfds[] = {
|
||||
[EVENT_LOOP_DBUS] = {
|
||||
.fd = sd_bus_get_fd(state.bus),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_WAYLAND] = {
|
||||
.fd = wl_display_get_fd(state.wl_display),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_PIPEWIRE] = {
|
||||
.fd = pw_loop_get_fd(state.pw_loop),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_TIMER] = {
|
||||
.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC),
|
||||
.events = POLLIN,
|
||||
}
|
||||
};
|
||||
wl_list_init(&state.timers);
|
||||
|
||||
state.timer_poll_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
||||
struct pollfd pollfds[] = {[EVENT_LOOP_DBUS] =
|
||||
{
|
||||
.fd = sd_bus_get_fd(state.bus),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_WAYLAND] =
|
||||
{
|
||||
.fd = wl_display_get_fd(state.wl_display),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_PIPEWIRE] =
|
||||
{
|
||||
.fd = pw_loop_get_fd(state.pw_loop),
|
||||
.events = POLLIN,
|
||||
},
|
||||
[EVENT_LOOP_TIMER] = {
|
||||
.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC),
|
||||
.events = POLLIN,
|
||||
}};
|
||||
|
||||
while (1) {
|
||||
ret = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), -1);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "poll failed: %s", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
state.timer_poll_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
||||
|
||||
if (pollfds[EVENT_LOOP_DBUS].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from dbus");
|
||||
break;
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_WAYLAND].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from wayland");
|
||||
break;
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_PIPEWIRE].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from pipewire");
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
ret = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), -1);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "poll failed: %s", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pollfds[EVENT_LOOP_DBUS].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got dbus event");
|
||||
do {
|
||||
ret = sd_bus_process(state.bus, NULL);
|
||||
} while (ret > 0);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "sd_bus_process failed: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_DBUS].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from dbus");
|
||||
break;
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_WAYLAND].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from wayland");
|
||||
break;
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_PIPEWIRE].revents & POLLHUP) {
|
||||
logprint(INFO, "event-loop: disconnected from pipewire");
|
||||
break;
|
||||
}
|
||||
|
||||
if (pollfds[EVENT_LOOP_WAYLAND].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got wayland event");
|
||||
ret = wl_display_dispatch(state.wl_display);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "wl_display_dispatch failed: %s", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_DBUS].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got dbus event");
|
||||
do {
|
||||
ret = sd_bus_process(state.bus, NULL);
|
||||
} while (ret > 0);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "sd_bus_process failed: %s", strerror(-ret));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfds[EVENT_LOOP_PIPEWIRE].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got pipewire event");
|
||||
ret = pw_loop_iterate(state.pw_loop, 0);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "pw_loop_iterate failed: %s", spa_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_WAYLAND].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got wayland event");
|
||||
ret = wl_display_dispatch(state.wl_display);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "wl_display_dispatch failed: %s", strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (pollfds[EVENT_LOOP_TIMER].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got a timer event");
|
||||
if (pollfds[EVENT_LOOP_PIPEWIRE].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got pipewire event");
|
||||
ret = pw_loop_iterate(state.pw_loop, 0);
|
||||
if (ret < 0) {
|
||||
logprint(ERROR, "pw_loop_iterate failed: %s", spa_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
int timer_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
||||
uint64_t expirations;
|
||||
ssize_t n = read(timer_fd, &expirations, sizeof(expirations));
|
||||
if (n < 0) {
|
||||
logprint(ERROR, "failed to read from timer FD\n");
|
||||
goto error;
|
||||
}
|
||||
if (pollfds[EVENT_LOOP_TIMER].revents & POLLIN) {
|
||||
logprint(TRACE, "event-loop: got a timer event");
|
||||
|
||||
struct xdpw_timer *timer = state.next_timer;
|
||||
if (timer != NULL) {
|
||||
xdpw_event_loop_timer_func_t func = timer->func;
|
||||
void *user_data = timer->user_data;
|
||||
xdpw_destroy_timer(timer);
|
||||
int timer_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
||||
uint64_t expirations;
|
||||
ssize_t n = read(timer_fd, &expirations, sizeof(expirations));
|
||||
if (n < 0) {
|
||||
logprint(ERROR, "failed to read from timer FD\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
func(user_data);
|
||||
}
|
||||
}
|
||||
struct xdpw_timer *timer = state.next_timer;
|
||||
if (timer != NULL) {
|
||||
xdpw_event_loop_timer_func_t func = timer->func;
|
||||
void *user_data = timer->user_data;
|
||||
xdpw_destroy_timer(timer);
|
||||
|
||||
do {
|
||||
ret = wl_display_dispatch_pending(state.wl_display);
|
||||
wl_display_flush(state.wl_display);
|
||||
} while (ret > 0);
|
||||
func(user_data);
|
||||
}
|
||||
}
|
||||
|
||||
sd_bus_flush(state.bus);
|
||||
}
|
||||
do {
|
||||
ret = wl_display_dispatch_pending(state.wl_display);
|
||||
wl_display_flush(state.wl_display);
|
||||
} while (ret > 0);
|
||||
|
||||
// TODO: cleanup
|
||||
finish_config(&config);
|
||||
free(configfile);
|
||||
sd_bus_flush(state.bus);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
// TODO: cleanup
|
||||
finish_config(&config);
|
||||
free(configfile);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
error:
|
||||
sd_bus_unref(bus);
|
||||
pw_loop_leave(state.pw_loop);
|
||||
pw_loop_destroy(state.pw_loop);
|
||||
wl_display_disconnect(state.wl_display);
|
||||
return EXIT_FAILURE;
|
||||
sd_bus_unref(bus);
|
||||
pw_loop_leave(state.pw_loop);
|
||||
pw_loop_destroy(state.pw_loop);
|
||||
wl_display_disconnect(state.wl_display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
|
537
src/globalshortcuts/global_shortcuts.c
Normal file
537
src/globalshortcuts/global_shortcuts.c
Normal file
|
@ -0,0 +1,537 @@
|
|||
#include "include/global_shortcuts.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "include/xdpw.h"
|
||||
|
||||
static void wlr_registry_handle_add(void *data, struct wl_registry *reg, uint32_t id, const char *interface, uint32_t ver) {
|
||||
struct globalShortcutsInstance *instance = data;
|
||||
|
||||
if (!strcmp(interface, hyprland_global_shortcuts_manager_v1_interface.name) && instance->manager == NULL) {
|
||||
uint32_t version = ver;
|
||||
|
||||
logprint(DEBUG, "hyprland: |-- registered to interface %s (Version %u)", interface, version);
|
||||
|
||||
instance->manager = wl_registry_bind(reg, id, &hyprland_global_shortcuts_manager_v1_interface, version);
|
||||
}
|
||||
}
|
||||
|
||||
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id) {
|
||||
; // ignored
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener wlr_registry_listener = {
|
||||
.global = wlr_registry_handle_add,
|
||||
.global_remove = wlr_registry_handle_remove,
|
||||
};
|
||||
|
||||
static const char object_path[] = "/org/freedesktop/portal/desktop";
|
||||
static const char interface_name[] = "org.freedesktop.impl.portal.GlobalShortcuts";
|
||||
|
||||
static int method_gs_create_session(sd_bus_message *msg, void *data, sd_bus_error *ret_error);
|
||||
static int method_gs_bind_shortcuts(sd_bus_message *msg, void *data, sd_bus_error *ret_error);
|
||||
static int method_gs_list_shortcuts(sd_bus_message *msg, void *data, sd_bus_error *ret_error);
|
||||
|
||||
static const sd_bus_vtable gs_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_METHOD("CreateSession", "oosa{sv}", "ua{sv}", method_gs_create_session, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("BindShortcuts", "ooa(sa{sv})sa{sv}", "ua{sv}", method_gs_bind_shortcuts, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("ListShortcuts", "oo", "ua{sv}", method_gs_list_shortcuts, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_SIGNAL("Activated", "osta{sv}", NULL),
|
||||
SD_BUS_SIGNAL("Deactivated", "osta{sv}", NULL),
|
||||
SD_BUS_SIGNAL("ShortcutsChanged", "oa(sa{sv})", NULL),
|
||||
SD_BUS_VTABLE_END};
|
||||
|
||||
static void handleActivated(void *data, struct hyprland_global_shortcut_v1 *hyprland_global_shortcut_v1, uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
||||
uint32_t tv_nsec) {
|
||||
struct xdpw_state *state = data;
|
||||
|
||||
bool found = false;
|
||||
|
||||
struct globalShortcut *curr;
|
||||
struct globalShortcutsClient *currc;
|
||||
wl_list_for_each(currc, &state->shortcutsInstance.shortcutClients, link) {
|
||||
wl_list_for_each(curr, &currc->shortcuts, link) {
|
||||
if (curr->hlShortcut == hyprland_global_shortcut_v1) {
|
||||
found = true;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
found:
|
||||
|
||||
if (!found) return;
|
||||
|
||||
sd_bus_emit_signal(state->bus, object_path, interface_name, "Activated", "osta{sv}", currc->session->session_handle, curr->name,
|
||||
((uint64_t)tv_sec_hi << 32) | (uint64_t)(tv_sec_lo), 0);
|
||||
}
|
||||
|
||||
static void handleDeactivated(void *data, struct hyprland_global_shortcut_v1 *hyprland_global_shortcut_v1, uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
||||
uint32_t tv_nsec) {
|
||||
struct xdpw_state *state = data;
|
||||
|
||||
bool found = false;
|
||||
|
||||
struct globalShortcut *curr;
|
||||
struct globalShortcutsClient *currc;
|
||||
wl_list_for_each(currc, &state->shortcutsInstance.shortcutClients, link) {
|
||||
wl_list_for_each(curr, &currc->shortcuts, link) {
|
||||
if (curr->hlShortcut == hyprland_global_shortcut_v1) {
|
||||
found = true;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
}
|
||||
found:
|
||||
|
||||
if (!found) return;
|
||||
|
||||
sd_bus_emit_signal(state->bus, object_path, interface_name, "Deactivated", "osta{sv}", currc->session->session_handle, curr->name,
|
||||
((uint64_t)tv_sec_hi << 32) | (uint64_t)(tv_sec_lo), 0);
|
||||
}
|
||||
|
||||
static const struct hyprland_global_shortcut_v1_listener shortcutListener = {
|
||||
.pressed = handleActivated,
|
||||
.released = handleDeactivated,
|
||||
};
|
||||
|
||||
static int method_gs_create_session(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||
struct xdpw_state *state = data;
|
||||
struct globalShortcutsClient *client = calloc(1, sizeof(struct globalShortcutsClient));
|
||||
wl_list_insert(&state->shortcutsInstance.shortcutClients, &client->link);
|
||||
wl_list_init(&client->shortcuts);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
logprint(INFO, "dbus: create session method invoked");
|
||||
|
||||
char *request_handle, *session_handle, *app_id;
|
||||
ret = sd_bus_message_read(msg, "oos", &request_handle, &session_handle, &app_id);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||
logprint(INFO, "dbus: app_id: %s", app_id);
|
||||
|
||||
char *key;
|
||||
char *option_token;
|
||||
int innerRet = 0;
|
||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
if (strcmp(key, "session_handle_token") == 0) {
|
||||
sd_bus_message_read(msg, "v", "s", &option_token);
|
||||
logprint(INFO, "dbus: option token: %s", option_token);
|
||||
} else if (strcmp(key, "shortcuts") == 0) {
|
||||
// init shortcuts
|
||||
client->sentShortcuts = true;
|
||||
|
||||
innerRet = sd_bus_message_enter_container(msg, 'v', "a(sa{sv})");
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_enter_container(msg, 'a', "(sa{sv})");
|
||||
|
||||
while (innerRet > 0) {
|
||||
char type;
|
||||
char *container;
|
||||
sd_bus_message_peek_type(msg, &type, &container);
|
||||
|
||||
if (type != 'r') break;
|
||||
|
||||
innerRet = sd_bus_message_enter_container(msg, 'r', "sa{sv}");
|
||||
if (innerRet == -ENXIO) break;
|
||||
|
||||
sd_bus_message_peek_type(msg, &type, &container);
|
||||
|
||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||
|
||||
if (innerRet == -ENXIO) break;
|
||||
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
logprint(DEBUG, "shortcut name %s", key);
|
||||
|
||||
struct globalShortcut *shortcut = calloc(1, sizeof(struct globalShortcut));
|
||||
shortcut->name = malloc(strlen(key) + 1);
|
||||
strcpy(shortcut->name, key);
|
||||
|
||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
if (strcmp(key, "description") == 0) {
|
||||
sd_bus_message_read(msg, "v", "s", &key);
|
||||
shortcut->description = malloc(strlen(key) + 1);
|
||||
strcpy(shortcut->description, key);
|
||||
} else {
|
||||
sd_bus_message_skip(msg, "v");
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
}
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
|
||||
if (shortcut->description == NULL) {
|
||||
shortcut->description = calloc(1, 1);
|
||||
}
|
||||
|
||||
wl_list_insert(&client->shortcuts, &shortcut->link);
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
} else {
|
||||
logprint(WARN, "dbus: unknown option: %s", key);
|
||||
sd_bus_message_skip(msg, "v");
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sd_bus_message_exit_container(msg);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct xdpw_request *req = xdpw_request_create(sd_bus_message_get_bus(msg), request_handle);
|
||||
if (req == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
struct xdpw_session *sess = xdpw_session_create(state, sd_bus_message_get_bus(msg), strdup(session_handle));
|
||||
if (sess == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
client->session = sess;
|
||||
|
||||
sess->app_id = malloc(strlen(app_id) + 1);
|
||||
strcpy(sess->app_id, app_id);
|
||||
|
||||
sd_bus_message *reply = NULL;
|
||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_append(reply, "u", PORTAL_RESPONSE_SUCCESS, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_open_container(reply, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
sd_bus_message_open_container(reply, 'e', "sv");
|
||||
sd_bus_message_append(reply, "s", "shortcuts");
|
||||
sd_bus_message_open_container(reply, 'v', "a(sa{sv})");
|
||||
sd_bus_message_open_container(reply, 'a', "(sa{sv})");
|
||||
struct globalShortcut *curr;
|
||||
wl_list_for_each(curr, &client->shortcuts, link) {
|
||||
sd_bus_message_append(reply, "(sa{sv})", curr->name, 1, "description", "s", curr->description);
|
||||
curr->hlShortcut = hyprland_global_shortcuts_manager_v1_register_shortcut(
|
||||
state->shortcutsInstance.manager, curr->name, (strlen(app_id) == 0 ? option_token : app_id), curr->description, "");
|
||||
hyprland_global_shortcut_v1_add_listener(curr->hlShortcut, &shortcutListener, state);
|
||||
curr->bound = true;
|
||||
}
|
||||
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_send(NULL, reply, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
sd_bus_message_unref(reply);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int method_gs_bind_shortcuts(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||
struct xdpw_state *state = data;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
logprint(INFO, "dbus: bind shortcuts invoked");
|
||||
|
||||
char *request_handle, *session_handle;
|
||||
ret = sd_bus_message_read(msg, "oo", &request_handle, &session_handle);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||
|
||||
struct xdpw_session *session, *tmp_session;
|
||||
wl_list_for_each_reverse_safe(session, tmp_session, &state->xdpw_sessions, link) {
|
||||
if (strcmp(session->session_handle, session_handle) == 0) {
|
||||
logprint(DEBUG, "dbus: bind shortcuts: found matching session %s", session->session_handle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct globalShortcutsClient *client, *tmp_client;
|
||||
wl_list_for_each_reverse_safe(client, tmp_client, &state->shortcutsInstance.shortcutClients, link) {
|
||||
if (strcmp(client->session, session_handle) == 0) {
|
||||
logprint(DEBUG, "dbus: bind shortcuts: found matching client %s", client->session);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client->sentShortcuts) {
|
||||
char *key;
|
||||
int innerRet = 0;
|
||||
client->sentShortcuts = true;
|
||||
|
||||
innerRet = sd_bus_message_enter_container(msg, 'a', "(sa{sv})");
|
||||
|
||||
while (innerRet > 0) {
|
||||
char type;
|
||||
char *container;
|
||||
sd_bus_message_peek_type(msg, &type, &container);
|
||||
|
||||
if (type != 'r') break;
|
||||
|
||||
innerRet = sd_bus_message_enter_container(msg, 'r', "sa{sv}");
|
||||
if (innerRet == -ENXIO) break;
|
||||
|
||||
sd_bus_message_peek_type(msg, &type, &container);
|
||||
|
||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||
|
||||
if (innerRet == -ENXIO) break;
|
||||
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
logprint(DEBUG, "shortcut name %s", key);
|
||||
|
||||
struct globalShortcut *shortcut = calloc(1, sizeof(struct globalShortcut));
|
||||
shortcut->name = malloc(strlen(key) + 1);
|
||||
strcpy(shortcut->name, key);
|
||||
|
||||
ret = sd_bus_message_enter_container(msg, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ((ret = sd_bus_message_enter_container(msg, 'e', "sv")) > 0) {
|
||||
innerRet = sd_bus_message_read(msg, "s", &key);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
|
||||
if (strcmp(key, "description") == 0) {
|
||||
sd_bus_message_read(msg, "v", "s", &key);
|
||||
shortcut->description = malloc(strlen(key) + 1);
|
||||
strcpy(shortcut->description, key);
|
||||
} else {
|
||||
sd_bus_message_skip(msg, "v");
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
}
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
|
||||
if (shortcut->description == NULL) {
|
||||
shortcut->description = calloc(1, 1);
|
||||
}
|
||||
|
||||
wl_list_insert(&client->shortcuts, &shortcut->link);
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
}
|
||||
|
||||
innerRet = sd_bus_message_exit_container(msg);
|
||||
if (innerRet < 0) {
|
||||
return innerRet;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sd_bus_message_exit_container(msg);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *parent_window;
|
||||
ret = sd_bus_message_read(msg, "s", &parent_window);
|
||||
|
||||
logprint(DEBUG, "dbus: parent_window %s", parent_window);
|
||||
|
||||
client->parent_window = malloc(strlen(parent_window) + 1);
|
||||
strcpy(client->parent_window, parent_window);
|
||||
|
||||
sd_bus_message *reply = NULL;
|
||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_append(reply, "u", PORTAL_RESPONSE_SUCCESS, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_open_container(reply, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
sd_bus_message_open_container(reply, 'e', "sv");
|
||||
sd_bus_message_append(reply, "s", "shortcuts");
|
||||
sd_bus_message_open_container(reply, 'v', "a(sa{sv})");
|
||||
sd_bus_message_open_container(reply, 'a', "(sa{sv})");
|
||||
struct globalShortcut *curr;
|
||||
wl_list_for_each(curr, &client->shortcuts, link) {
|
||||
sd_bus_message_append(reply, "(sa{sv})", curr->name, 1, "description", "s", curr->description);
|
||||
if (!curr->bound) {
|
||||
curr->hlShortcut = hyprland_global_shortcuts_manager_v1_register_shortcut(state->shortcutsInstance.manager, curr->name, parent_window,
|
||||
curr->description, "");
|
||||
hyprland_global_shortcut_v1_add_listener(curr->hlShortcut, &shortcutListener, state);
|
||||
}
|
||||
}
|
||||
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_send(NULL, reply, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int method_gs_list_shortcuts(sd_bus_message *msg, void *data, sd_bus_error *ret_error) {
|
||||
struct xdpw_state *state = data;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
logprint(INFO, "dbus: list shortcuts invoked");
|
||||
|
||||
char *request_handle, *session_handle;
|
||||
ret = sd_bus_message_read(msg, "oo", &request_handle, &session_handle);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
logprint(INFO, "dbus: request_handle: %s", request_handle);
|
||||
logprint(INFO, "dbus: session_handle: %s", session_handle);
|
||||
|
||||
bool foundClient = false;
|
||||
struct globalShortcutsClient *client, *tmp_client;
|
||||
wl_list_for_each(client, &state->shortcutsInstance.shortcutClients, link) {
|
||||
if (strcmp(client->session, session_handle) == 0) {
|
||||
logprint(DEBUG, "dbus: bind shortcuts: found matching client %s", client->session);
|
||||
foundClient = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundClient || !client->sentShortcuts) return 0;
|
||||
|
||||
sd_bus_message *reply = NULL;
|
||||
ret = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_append(reply, "u", PORTAL_RESPONSE_SUCCESS, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_message_open_container(reply, 'a', "{sv}");
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
sd_bus_message_open_container(reply, 'e', "sv");
|
||||
sd_bus_message_append(reply, "s", "shortcuts");
|
||||
sd_bus_message_open_container(reply, 'v', "a(sa{sv})");
|
||||
sd_bus_message_open_container(reply, 'a', "(sa{sv})");
|
||||
struct globalShortcut *curr;
|
||||
wl_list_for_each(curr, &client->shortcuts, link) {
|
||||
sd_bus_message_append(reply, "(sa{sv})", curr->name, 1, "description", "s", curr->description);
|
||||
}
|
||||
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
ret = sd_bus_message_close_container(reply);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = sd_bus_send(NULL, reply, NULL);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initShortcutsInstance(struct xdpw_state *state, struct globalShortcutsInstance *instance) {
|
||||
instance->manager = NULL;
|
||||
wl_list_init(&instance->shortcutClients);
|
||||
|
||||
struct wl_registry *registry = wl_display_get_registry(state->wl_display);
|
||||
wl_registry_add_listener(registry, &wlr_registry_listener, instance);
|
||||
|
||||
wl_display_roundtrip(state->wl_display);
|
||||
|
||||
if (instance->manager == NULL) {
|
||||
logprint(ERROR, "hyprland shortcut protocol unavailable!");
|
||||
return;
|
||||
}
|
||||
|
||||
sd_bus_slot *slot = NULL;
|
||||
int ret = sd_bus_add_object_vtable(state->bus, &slot, object_path, interface_name, gs_vtable, state);
|
||||
|
||||
logprint(DEBUG, "dbus: gs: ret bind %d", ret);
|
||||
|
||||
// register to hl
|
||||
}
|
|
@ -41,8 +41,7 @@ void handleTitle(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, con
|
|||
if (current->handle == handle) {
|
||||
strncpy(current->name, title, 255);
|
||||
for (int i = 0; i < 255; ++i)
|
||||
if (current->name[i] == '\"' || current->name[i] == '>' || current->name[i] == '\'')
|
||||
current->name[i] = ' ';
|
||||
if (current->name[i] == '\"' || current->name[i] == '>' || current->name[i] == '\'') current->name[i] = ' ';
|
||||
current->name[255] = '\0';
|
||||
break;
|
||||
}
|
||||
|
@ -57,8 +56,7 @@ void handleAppID(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, con
|
|||
if (current->handle == handle) {
|
||||
strncpy(current->clazz, app_id, 255);
|
||||
for (int i = 0; i < 255; ++i)
|
||||
if (current->clazz[i] == '\"' || current->clazz[i] == '>' || current->clazz[i] == '\'')
|
||||
current->clazz[i] = ' ';
|
||||
if (current->clazz[i] == '\"' || current->clazz[i] == '>' || current->clazz[i] == '\'') current->clazz[i] = ' ';
|
||||
current->name[255] = '\0';
|
||||
break;
|
||||
}
|
||||
|
@ -187,8 +185,7 @@ void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast) {
|
|||
xdpw_pwr_enqueue_buffer(cast);
|
||||
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
|
||||
if (delay_ns > 0) {
|
||||
xdpw_add_timer(cast->ctx->state, delay_ns,
|
||||
(xdpw_event_loop_timer_func_t)xdpw_wlr_frame_start, cast);
|
||||
xdpw_add_timer(cast->ctx->state, delay_ns, (xdpw_event_loop_timer_func_t)xdpw_wlr_frame_start, cast);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -211,11 +208,9 @@ void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast) {
|
|||
xdpw_wlr_register_cb(cast);
|
||||
}
|
||||
|
||||
static void wlr_frame_buffer_done(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *frame);
|
||||
static void wlr_frame_buffer_done(void *data, struct zwlr_screencopy_frame_v1 *frame);
|
||||
|
||||
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
||||
static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -235,9 +230,7 @@ static void wlr_frame_buffer(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
|||
}
|
||||
}
|
||||
|
||||
static void wlr_frame_linux_dmabuf(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t format, uint32_t width, uint32_t height) {
|
||||
static void wlr_frame_linux_dmabuf(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t format, uint32_t width, uint32_t height) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -250,8 +243,7 @@ static void wlr_frame_linux_dmabuf(void *data,
|
|||
cast->screencopy_frame_info[DMABUF].format = format;
|
||||
}
|
||||
|
||||
static void wlr_frame_buffer_done(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *frame) {
|
||||
static void wlr_frame_buffer_done(void *data, struct zwlr_screencopy_frame_v1 *frame) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -266,7 +258,8 @@ static void wlr_frame_buffer_done(void *data,
|
|||
|
||||
// Check if announced screencopy information is compatible with pipewire meta
|
||||
if ((cast->pwr_format.format != xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format) &&
|
||||
cast->pwr_format.format != xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format))) ||
|
||||
cast->pwr_format.format !=
|
||||
xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format))) ||
|
||||
cast->pwr_format.size.width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
||||
|
@ -288,9 +281,8 @@ static void wlr_frame_buffer_done(void *data,
|
|||
assert(cast->current_frame.xdpw_buffer);
|
||||
|
||||
// Check if dequeued buffer is compatible with announced buffer
|
||||
if ((cast->buffer_type == WL_SHM &&
|
||||
(cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
|
||||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
|
||||
if ((cast->buffer_type == WL_SHM && (cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
|
||||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
|
||||
cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||
logprint(DEBUG, "wlroots: pipewire buffer has wrong dimensions");
|
||||
|
@ -305,8 +297,7 @@ static void wlr_frame_buffer_done(void *data,
|
|||
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
||||
}
|
||||
|
||||
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t flags) {
|
||||
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t flags) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -316,8 +307,7 @@ static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
|||
cast->current_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||
}
|
||||
|
||||
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
||||
static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -331,8 +321,7 @@ static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
|||
cast->current_frame.damage.height = height;
|
||||
}
|
||||
|
||||
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -349,8 +338,7 @@ static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
|||
xdpw_wlr_frame_finish(cast);
|
||||
}
|
||||
|
||||
static void wlr_frame_failed(void *data,
|
||||
struct zwlr_screencopy_frame_v1 *frame) {
|
||||
static void wlr_frame_failed(void *data, struct zwlr_screencopy_frame_v1 *frame) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -373,11 +361,10 @@ static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
|||
.damage = wlr_frame_damage,
|
||||
};
|
||||
|
||||
static void hyprland_frame_buffer_done(void *data,
|
||||
struct hyprland_toplevel_export_frame_v1 *frame);
|
||||
static void hyprland_frame_buffer_done(void *data, struct hyprland_toplevel_export_frame_v1 *frame);
|
||||
|
||||
static void hyprland_frame_buffer(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
||||
uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
||||
static void hyprland_frame_buffer(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t format, uint32_t width, uint32_t height,
|
||||
uint32_t stride) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -396,9 +383,8 @@ static void hyprland_frame_buffer(void *data, struct hyprland_toplevel_export_fr
|
|||
hyprland_frame_buffer_done(cast, frame);
|
||||
}
|
||||
|
||||
static void hyprland_frame_linux_dmabuf(void *data,
|
||||
struct hyprland_toplevel_export_frame_v1 *frame,
|
||||
uint32_t format, uint32_t width, uint32_t height) {
|
||||
static void hyprland_frame_linux_dmabuf(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t format, uint32_t width,
|
||||
uint32_t height) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -411,8 +397,7 @@ static void hyprland_frame_linux_dmabuf(void *data,
|
|||
cast->screencopy_frame_info[DMABUF].format = format;
|
||||
}
|
||||
|
||||
static void hyprland_frame_buffer_done(void *data,
|
||||
struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||
static void hyprland_frame_buffer_done(void *data, struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -427,7 +412,8 @@ static void hyprland_frame_buffer_done(void *data,
|
|||
|
||||
// Check if announced screencopy information is compatible with pipewire meta
|
||||
if ((cast->pwr_format.format != xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format) &&
|
||||
cast->pwr_format.format != xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format))) ||
|
||||
cast->pwr_format.format !=
|
||||
xdpw_format_pw_strip_alpha(xdpw_format_pw_from_drm_fourcc(cast->screencopy_frame_info[cast->buffer_type].format))) ||
|
||||
cast->pwr_format.size.width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||
logprint(DEBUG, "hyprland: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
||||
|
@ -449,9 +435,8 @@ static void hyprland_frame_buffer_done(void *data,
|
|||
assert(cast->current_frame.xdpw_buffer);
|
||||
|
||||
// Check if dequeued buffer is compatible with announced buffer
|
||||
if ((cast->buffer_type == WL_SHM &&
|
||||
(cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
|
||||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
|
||||
if ((cast->buffer_type == WL_SHM && (cast->current_frame.xdpw_buffer->size[0] != cast->screencopy_frame_info[cast->buffer_type].size ||
|
||||
cast->current_frame.xdpw_buffer->stride[0] != cast->screencopy_frame_info[cast->buffer_type].stride)) ||
|
||||
cast->current_frame.xdpw_buffer->width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||
logprint(DEBUG, "hyprland: pipewire buffer has wrong dimensions");
|
||||
|
@ -466,8 +451,7 @@ static void hyprland_frame_buffer_done(void *data,
|
|||
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
||||
}
|
||||
|
||||
static void hyprland_frame_flags(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
||||
uint32_t flags) {
|
||||
static void hyprland_frame_flags(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t flags) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -477,8 +461,8 @@ static void hyprland_frame_flags(void *data, struct hyprland_toplevel_export_fra
|
|||
cast->current_frame.y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||
}
|
||||
|
||||
static void hyprland_frame_damage(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
||||
uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
||||
static void hyprland_frame_damage(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -492,8 +476,8 @@ static void hyprland_frame_damage(void *data, struct hyprland_toplevel_export_fr
|
|||
cast->current_frame.damage.height = height;
|
||||
}
|
||||
|
||||
static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
||||
static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t tv_sec_hi, uint32_t tv_sec_lo,
|
||||
uint32_t tv_nsec) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -510,8 +494,7 @@ static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_fra
|
|||
xdpw_wlr_frame_finish(cast);
|
||||
}
|
||||
|
||||
static void hyprland_frame_failed(void *data,
|
||||
struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||
static void hyprland_frame_failed(void *data, struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||
struct xdpw_screencast_instance *cast = data;
|
||||
if (!frame) {
|
||||
return;
|
||||
|
@ -524,24 +507,23 @@ static void hyprland_frame_failed(void *data,
|
|||
xdpw_wlr_frame_finish(cast);
|
||||
}
|
||||
|
||||
static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_listener = {
|
||||
.buffer = hyprland_frame_buffer,
|
||||
.buffer_done = hyprland_frame_buffer_done,
|
||||
.linux_dmabuf = hyprland_frame_linux_dmabuf,
|
||||
.flags = hyprland_frame_flags,
|
||||
.ready = hyprland_frame_ready,
|
||||
.failed = hyprland_frame_failed,
|
||||
.damage = hyprland_frame_damage};
|
||||
static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_listener = {.buffer = hyprland_frame_buffer,
|
||||
.buffer_done = hyprland_frame_buffer_done,
|
||||
.linux_dmabuf = hyprland_frame_linux_dmabuf,
|
||||
.flags = hyprland_frame_flags,
|
||||
.ready = hyprland_frame_ready,
|
||||
.failed = hyprland_frame_failed,
|
||||
.damage = hyprland_frame_damage};
|
||||
|
||||
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
|
||||
if (cast->target.x != -1 && cast->target.y != -1 && cast->target.w != -1 && cast->target.h != -1 && cast->target.window_handle <= 0) {
|
||||
// capture region
|
||||
cast->frame_callback = zwlr_screencopy_manager_v1_capture_output_region(
|
||||
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output, cast->target.x,
|
||||
cast->target.y, cast->target.w, cast->target.h);
|
||||
cast->frame_callback =
|
||||
zwlr_screencopy_manager_v1_capture_output_region(cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output,
|
||||
cast->target.x, cast->target.y, cast->target.w, cast->target.h);
|
||||
} else if (cast->target.window_handle == -1) {
|
||||
cast->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
||||
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
|
||||
cast->frame_callback =
|
||||
zwlr_screencopy_manager_v1_capture_output(cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
|
||||
} else {
|
||||
// share window
|
||||
struct SToplevelEntry *entry = toplevelEntryFromID(cast->ctx, cast->target.window_handle);
|
||||
|
@ -554,41 +536,34 @@ void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
|
|||
cast->frame_callback_hyprland = hyprland_toplevel_export_manager_v1_capture_toplevel_with_wlr_toplevel_handle(
|
||||
cast->ctx->hyprland_toplevel_manager, cast->with_cursor, entry->handle);
|
||||
|
||||
hyprland_toplevel_export_frame_v1_add_listener(cast->frame_callback_hyprland,
|
||||
&hyprland_frame_listener, cast);
|
||||
hyprland_toplevel_export_frame_v1_add_listener(cast->frame_callback_hyprland, &hyprland_frame_listener, cast);
|
||||
|
||||
logprint(TRACE, "hyprland: callbacks registered");
|
||||
return;
|
||||
}
|
||||
|
||||
zwlr_screencopy_frame_v1_add_listener(cast->frame_callback,
|
||||
&wlr_frame_listener, cast);
|
||||
zwlr_screencopy_frame_v1_add_listener(cast->frame_callback, &wlr_frame_listener, cast);
|
||||
logprint(TRACE, "wlroots: callbacks registered");
|
||||
}
|
||||
|
||||
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output,
|
||||
int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
|
||||
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t phys_width, int32_t phys_height,
|
||||
int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
||||
struct xdpw_wlr_output *output = data;
|
||||
output->make = strdup(make);
|
||||
output->model = strdup(model);
|
||||
}
|
||||
|
||||
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
|
||||
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||
struct xdpw_wlr_output *output = data;
|
||||
output->framerate = (float)refresh / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void wlr_output_handle_done(void *data, struct wl_output *wl_output) {
|
||||
/* Nothing to do */
|
||||
static void wlr_output_handle_done(void *data, struct wl_output *wl_output) { /* Nothing to do */
|
||||
}
|
||||
|
||||
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output,
|
||||
int32_t factor) {
|
||||
/* Nothing to do */
|
||||
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { /* Nothing to do */
|
||||
}
|
||||
|
||||
static const struct wl_output_listener wlr_output_listener = {
|
||||
|
@ -598,8 +573,7 @@ static const struct wl_output_listener wlr_output_listener = {
|
|||
.scale = wlr_output_handle_scale,
|
||||
};
|
||||
|
||||
static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
const char *name) {
|
||||
static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) {
|
||||
struct xdpw_wlr_output *output = data;
|
||||
|
||||
output->name = strdup(name);
|
||||
|
@ -617,18 +591,13 @@ static const struct zxdg_output_v1_listener wlr_xdg_output_listener = {
|
|||
.name = wlr_xdg_output_name,
|
||||
};
|
||||
|
||||
static void wlr_add_xdg_output_listener(struct xdpw_wlr_output *output,
|
||||
struct zxdg_output_v1 *xdg_output) {
|
||||
static void wlr_add_xdg_output_listener(struct xdpw_wlr_output *output, struct zxdg_output_v1 *xdg_output) {
|
||||
output->xdg_output = xdg_output;
|
||||
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener,
|
||||
output);
|
||||
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener, output);
|
||||
}
|
||||
|
||||
static void wlr_init_xdg_output(struct xdpw_screencast_context *ctx,
|
||||
struct xdpw_wlr_output *output) {
|
||||
struct zxdg_output_v1 *xdg_output =
|
||||
zxdg_output_manager_v1_get_xdg_output(ctx->xdg_output_manager,
|
||||
output->output);
|
||||
static void wlr_init_xdg_output(struct xdpw_screencast_context *ctx, struct xdpw_wlr_output *output) {
|
||||
struct zxdg_output_v1 *xdg_output = zxdg_output_manager_v1_get_xdg_output(ctx->xdg_output_manager, output->output);
|
||||
wlr_add_xdg_output_listener(output, xdg_output);
|
||||
}
|
||||
|
||||
|
@ -682,8 +651,7 @@ char *getFormat(const char *fmt, ...) {
|
|||
char *buildWindowList(struct xdpw_screencast_context *ctx) {
|
||||
char *rolling = calloc(1, 1);
|
||||
|
||||
if (!ctx->wlroots_toplevel_manager)
|
||||
return rolling;
|
||||
if (!ctx->wlroots_toplevel_manager) return rolling;
|
||||
|
||||
struct SToplevelEntry *current;
|
||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
||||
|
@ -695,8 +663,7 @@ char *buildWindowList(struct xdpw_screencast_context *ctx) {
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < strlen(rolling); ++i) {
|
||||
if (rolling[i] == '\"')
|
||||
rolling[i] = ' ';
|
||||
if (rolling[i] == '\"') rolling[i] = ' ';
|
||||
}
|
||||
|
||||
return rolling;
|
||||
|
@ -713,7 +680,10 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
|
||||
char *windowList = buildWindowList(ctx);
|
||||
|
||||
char *cmd = getFormat("WAYLAND_DISPLAY=%s QT_QPA_PLATFORM=\"wayland\" XCURSOR_SIZE=%s HYPRLAND_INSTANCE_SIGNATURE=%s XDPH_WINDOW_SHARING_LIST=\"%s\" hyprland-share-picker", WAYLAND_DISPLAY, XCURSOR_SIZE ? XCURSOR_SIZE : "24", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0", windowList);
|
||||
char *cmd = getFormat(
|
||||
"WAYLAND_DISPLAY=%s QT_QPA_PLATFORM=\"wayland\" XCURSOR_SIZE=%s HYPRLAND_INSTANCE_SIGNATURE=%s XDPH_WINDOW_SHARING_LIST=\"%s\" "
|
||||
"hyprland-share-picker",
|
||||
WAYLAND_DISPLAY, XCURSOR_SIZE ? XCURSOR_SIZE : "24", HYPRLAND_INSTANCE_SIGNATURE ? HYPRLAND_INSTANCE_SIGNATURE : "0", windowList);
|
||||
|
||||
free(windowList);
|
||||
|
||||
|
@ -756,8 +726,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
|
||||
free(display_name);
|
||||
|
||||
if (!found)
|
||||
return res;
|
||||
if (!found) return res;
|
||||
|
||||
res.output = out;
|
||||
return res;
|
||||
|
@ -832,14 +801,11 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
|||
|
||||
struct xdpw_wlr_output *xdpw_wlr_output_first(struct wl_list *output_list) {
|
||||
struct xdpw_wlr_output *output, *tmp;
|
||||
wl_list_for_each_safe(output, tmp, output_list, link) {
|
||||
return output;
|
||||
}
|
||||
wl_list_for_each_safe(output, tmp, output_list, link) { return output; }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list,
|
||||
const char *name) {
|
||||
struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list, const char *name) {
|
||||
struct xdpw_wlr_output *output, *tmp;
|
||||
wl_list_for_each_safe(output, tmp, output_list, link) {
|
||||
if (strcmp(output->name, name) == 0) {
|
||||
|
@ -849,8 +815,7 @@ struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx,
|
||||
struct wl_output *out, uint32_t id) {
|
||||
struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx, struct wl_output *out, uint32_t id) {
|
||||
struct xdpw_wlr_output *output, *tmp;
|
||||
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
||||
if ((output->output == out) || (output->id == id)) {
|
||||
|
@ -870,8 +835,7 @@ static void wlr_remove_output(struct xdpw_wlr_output *out) {
|
|||
free(out);
|
||||
}
|
||||
|
||||
static void wlr_format_modifier_pair_add(struct xdpw_screencast_context *ctx,
|
||||
uint32_t format, uint64_t modifier) {
|
||||
static void wlr_format_modifier_pair_add(struct xdpw_screencast_context *ctx, uint32_t format, uint64_t modifier) {
|
||||
struct xdpw_format_modifier_pair *fm_pair;
|
||||
wl_array_for_each(fm_pair, &ctx->format_modifier_pairs) {
|
||||
if (fm_pair->fourcc == format && fm_pair->modifier == modifier) {
|
||||
|
@ -886,9 +850,8 @@ static void wlr_format_modifier_pair_add(struct xdpw_screencast_context *ctx,
|
|||
logprint(TRACE, "wlroots: format %u (%lu)", fm_pair->fourcc, fm_pair->modifier);
|
||||
}
|
||||
|
||||
static void linux_dmabuf_handle_modifier(void *data,
|
||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1,
|
||||
uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) {
|
||||
static void linux_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi,
|
||||
uint32_t modifier_lo) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(TRACE, "wlroots: linux_dmabuf_handle_modifier called");
|
||||
|
@ -902,8 +865,8 @@ static const struct zwp_linux_dmabuf_v1_listener linux_dmabuf_listener = {
|
|||
.modifier = linux_dmabuf_handle_modifier,
|
||||
};
|
||||
|
||||
static void linux_dmabuf_feedback_handle_main_device(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *device_arr) {
|
||||
static void linux_dmabuf_feedback_handle_main_device(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *device_arr) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_handle_main_device called");
|
||||
|
@ -923,8 +886,7 @@ static void linux_dmabuf_feedback_handle_main_device(void *data,
|
|||
ctx->gbm = xdpw_gbm_device_create(drmDev);
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_format_table(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, int fd, uint32_t size) {
|
||||
static void linux_dmabuf_feedback_format_table(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, int fd, uint32_t size) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_format_table called");
|
||||
|
@ -941,8 +903,7 @@ static void linux_dmabuf_feedback_format_table(void *data,
|
|||
ctx->feedback_data.format_table_size = size;
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_handle_done(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||
static void linux_dmabuf_feedback_handle_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_handle_done called");
|
||||
|
@ -954,8 +915,8 @@ static void linux_dmabuf_feedback_handle_done(void *data,
|
|||
ctx->feedback_data.format_table_size = 0;
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_tranche_target_devices(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *device_arr) {
|
||||
static void linux_dmabuf_feedback_tranche_target_devices(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *device_arr) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_target_devices called");
|
||||
|
@ -979,13 +940,12 @@ static void linux_dmabuf_feedback_tranche_target_devices(void *data,
|
|||
}
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_tranche_flags(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, uint32_t flags) {
|
||||
static void linux_dmabuf_feedback_tranche_flags(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, uint32_t flags) {
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_flags called");
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_tranche_formats(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *indices) {
|
||||
static void linux_dmabuf_feedback_tranche_formats(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||
struct wl_array *indices) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_formats called");
|
||||
|
@ -1012,8 +972,7 @@ static void linux_dmabuf_feedback_tranche_formats(void *data,
|
|||
}
|
||||
}
|
||||
|
||||
static void linux_dmabuf_feedback_tranche_done(void *data,
|
||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||
static void linux_dmabuf_feedback_tranche_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_done called");
|
||||
|
@ -1031,8 +990,7 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener linux_dmabuf_listener_
|
|||
.tranche_done = linux_dmabuf_feedback_tranche_done,
|
||||
};
|
||||
|
||||
static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
||||
uint32_t id, const char *interface, uint32_t ver) {
|
||||
static void wlr_registry_handle_add(void *data, struct wl_registry *reg, uint32_t id, const char *interface, uint32_t ver) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
|
||||
logprint(DEBUG, "wlroots: interface to register %s (Version: %u)", interface, ver);
|
||||
|
@ -1058,8 +1016,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
|||
version = SC_MANAGER_VERSION_MIN;
|
||||
}
|
||||
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, version);
|
||||
ctx->screencopy_manager = wl_registry_bind(
|
||||
reg, id, &zwlr_screencopy_manager_v1_interface, version);
|
||||
ctx->screencopy_manager = wl_registry_bind(reg, id, &zwlr_screencopy_manager_v1_interface, version);
|
||||
}
|
||||
|
||||
if (!strcmp(interface, hyprland_toplevel_export_manager_v1_interface.name) && !ctx->hyprland_toplevel_manager) {
|
||||
|
@ -1088,8 +1045,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
|||
|
||||
if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
|
||||
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, XDG_OUTPUT_MANAGER_VERSION);
|
||||
ctx->xdg_output_manager =
|
||||
wl_registry_bind(reg, id, &zxdg_output_manager_v1_interface, XDG_OUTPUT_MANAGER_VERSION);
|
||||
ctx->xdg_output_manager = wl_registry_bind(reg, id, &zxdg_output_manager_v1_interface, XDG_OUTPUT_MANAGER_VERSION);
|
||||
}
|
||||
if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
|
||||
uint32_t version = ver;
|
||||
|
@ -1111,8 +1067,7 @@ static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
|||
}
|
||||
}
|
||||
|
||||
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg,
|
||||
uint32_t id) {
|
||||
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id) {
|
||||
struct xdpw_screencast_context *ctx = data;
|
||||
struct xdpw_wlr_output *output = xdpw_wlr_output_find(ctx, NULL, id);
|
||||
if (output) {
|
||||
|
@ -1164,8 +1119,7 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) {
|
|||
|
||||
// make sure our wlroots supports xdg_output_manager
|
||||
if (!ctx->xdg_output_manager) {
|
||||
logprint(ERROR, "Compositor doesn't support %s!",
|
||||
zxdg_output_manager_v1_interface.name);
|
||||
logprint(ERROR, "Compositor doesn't support %s!", zxdg_output_manager_v1_interface.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1183,8 +1137,7 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) {
|
|||
|
||||
// make sure our wlroots supports screencopy protocol
|
||||
if (!ctx->screencopy_manager) {
|
||||
logprint(ERROR, "Compositor doesn't support %s!",
|
||||
zwlr_screencopy_manager_v1_interface.name);
|
||||
logprint(ERROR, "Compositor doesn't support %s!", zwlr_screencopy_manager_v1_interface.name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1210,9 +1163,7 @@ void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx) {
|
|||
}
|
||||
|
||||
struct xdpw_screencast_instance *cast, *tmp_c;
|
||||
wl_list_for_each_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
||||
cast->quit = true;
|
||||
}
|
||||
wl_list_for_each_safe(cast, tmp_c, &ctx->screencast_instances, link) { cast->quit = true; }
|
||||
|
||||
if (ctx->screencopy_manager) {
|
||||
zwlr_screencopy_manager_v1_destroy(ctx->screencopy_manager);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit b8f55e02a328c47ed373133c52483bbfa20a1b75
|
||||
Subproject commit d7d403b711b60e8136295b0d4229e89a115e80cc
|
Loading…
Reference in a new issue