mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2024-11-23 14:55:57 +01:00
initial impl
This commit is contained in:
parent
85f49f4d6c
commit
d16feeefbd
9 changed files with 944 additions and 396 deletions
|
@ -1,4 +1,4 @@
|
||||||
[portal]
|
[portal]
|
||||||
DBusName=org.freedesktop.impl.portal.desktop.hyprland
|
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;
|
UseIn=wlroots;Hyprland;sway;Wayfire;river;
|
||||||
|
|
28
include/global_shortcuts.h
Normal file
28
include/global_shortcuts.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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,9 +10,10 @@
|
||||||
#include <basu/sd-bus.h>
|
#include <basu/sd-bus.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "global_shortcuts.h"
|
||||||
#include "screencast_common.h"
|
#include "screencast_common.h"
|
||||||
#include "screenshot_common.h"
|
#include "screenshot_common.h"
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
struct xdpw_state {
|
struct xdpw_state {
|
||||||
struct wl_list xdpw_sessions;
|
struct wl_list xdpw_sessions;
|
||||||
|
@ -28,6 +29,7 @@ struct xdpw_state {
|
||||||
int timer_poll_fd;
|
int timer_poll_fd;
|
||||||
struct wl_list timers;
|
struct wl_list timers;
|
||||||
struct xdpw_timer *next_timer;
|
struct xdpw_timer *next_timer;
|
||||||
|
struct globalShortcutsInstance shortcutsInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xdpw_request {
|
struct xdpw_request {
|
||||||
|
@ -38,6 +40,7 @@ struct xdpw_session {
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
sd_bus_slot *slot;
|
sd_bus_slot *slot;
|
||||||
char *session_handle;
|
char *session_handle;
|
||||||
|
char *app_id;
|
||||||
struct xdpw_screencast_instance *screencast_instance;
|
struct xdpw_screencast_instance *screencast_instance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,11 +54,7 @@ struct xdpw_timer {
|
||||||
struct wl_list link; // xdpw_state::timers
|
struct wl_list link; // xdpw_state::timers
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum { PORTAL_RESPONSE_SUCCESS = 0, PORTAL_RESPONSE_CANCELLED = 1, PORTAL_RESPONSE_ENDED = 2 };
|
||||||
PORTAL_RESPONSE_SUCCESS = 0,
|
|
||||||
PORTAL_RESPONSE_CANCELLED = 1,
|
|
||||||
PORTAL_RESPONSE_ENDED = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
int xdpw_screenshot_init(struct xdpw_state *state);
|
int xdpw_screenshot_init(struct xdpw_state *state);
|
||||||
int xdpw_screencast_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);
|
struct xdpw_session *xdpw_session_create(struct xdpw_state *state, sd_bus *bus, char *object_path);
|
||||||
void xdpw_session_destroy(struct xdpw_session *req);
|
void xdpw_session_destroy(struct xdpw_session *req);
|
||||||
|
|
||||||
struct xdpw_timer *xdpw_add_timer(struct xdpw_state *state,
|
struct xdpw_timer *xdpw_add_timer(struct xdpw_state *state, uint64_t delay_ns, xdpw_event_loop_timer_func_t func, void *data);
|
||||||
uint64_t delay_ns, xdpw_event_loop_timer_func_t func, void *data);
|
|
||||||
|
|
||||||
void xdpw_destroy_timer(struct xdpw_timer *timer);
|
void xdpw_destroy_timer(struct xdpw_timer *timer);
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ xdpw_files = files([
|
||||||
'src/screencast/wlr_screencast.c',
|
'src/screencast/wlr_screencast.c',
|
||||||
'src/screencast/pipewire_screencast.c',
|
'src/screencast/pipewire_screencast.c',
|
||||||
'src/screencast/fps_limit.c',
|
'src/screencast/fps_limit.c',
|
||||||
|
'src/globalshortcuts/global_shortcuts.c'
|
||||||
])
|
])
|
||||||
|
|
||||||
executable(
|
executable(
|
||||||
|
|
112
protocols/hyprland-global-shortcuts-v1.xml
Normal file
112
protocols/hyprland-global-shortcuts-v1.xml
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="hyprland_global_shortcuts_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2022 Vaxry
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="registering global shortcuts">
|
||||||
|
This protocol allows a client to register triggerable actions,
|
||||||
|
meant to be global shortcuts.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="hyprland_global_shortcuts_manager_v1" version="1">
|
||||||
|
<description summary="manager to register global shortcuts">
|
||||||
|
This object is a manager which offers requests to create global shortcuts.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="register_shortcut">
|
||||||
|
<description summary="register a shortcut">
|
||||||
|
Register a new global shortcut.
|
||||||
|
|
||||||
|
A global shortcut is anonymous, meaning the app does not know what key(s) trigger it.
|
||||||
|
|
||||||
|
The shortcut's keybinding shall be dealt with by the compositor.
|
||||||
|
|
||||||
|
In the case of a duplicate app_id + id combination, the already_taken protocol error is raised.
|
||||||
|
</description>
|
||||||
|
<arg name="shortcut" type="new_id" interface="hyprland_global_shortcut_v1"/>
|
||||||
|
<arg name="id" type="string" summary="a unique id for the shortcut"/>
|
||||||
|
<arg name="app_id" type="string" summary="the app_id of the application requesting the shortcut"/>
|
||||||
|
<arg name="description" type="string" summary="user-readable text describing what the shortcut does."/>
|
||||||
|
<arg name="trigger_description" type="string" summary="user-readable text describing how to trigger the shortcut for the client to render."/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the manager">
|
||||||
|
All objects created by the manager will still remain valid, until their
|
||||||
|
appropriate destroy request has been called.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_taken" value="0"
|
||||||
|
summary="the app_id + id combination has already been registered."/>
|
||||||
|
</enum>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="hyprland_global_shortcut_v1" version="1">
|
||||||
|
<description summary="a shortcut">
|
||||||
|
This object represents a single shortcut.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="pressed">
|
||||||
|
<description summary="keystroke pressed">
|
||||||
|
The keystroke was pressed.
|
||||||
|
|
||||||
|
tv_ values hold the timestamp of the occurrence.
|
||||||
|
</description>
|
||||||
|
<arg name="tv_sec_hi" type="uint"
|
||||||
|
summary="high 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_sec_lo" type="uint"
|
||||||
|
summary="low 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_nsec" type="uint"
|
||||||
|
summary="nanoseconds part of the timestamp"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="released">
|
||||||
|
<description summary="keystroke released">
|
||||||
|
The keystroke was released.
|
||||||
|
|
||||||
|
tv_ values hold the timestamp of the occurrence.
|
||||||
|
</description>
|
||||||
|
<arg name="tv_sec_hi" type="uint"
|
||||||
|
summary="high 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_sec_lo" type="uint"
|
||||||
|
summary="low 32 bits of the seconds part of the timestamp"/>
|
||||||
|
<arg name="tv_nsec" type="uint"
|
||||||
|
summary="nanoseconds part of the timestamp"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="delete this object, used or not">
|
||||||
|
Destroys the shortcut. Can be sent at any time by the client.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
|
@ -17,6 +17,7 @@ client_protocols = [
|
||||||
hl_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
|
hl_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
|
||||||
'wlr-screencopy-unstable-v1.xml',
|
'wlr-screencopy-unstable-v1.xml',
|
||||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||||
|
'hyprland-global-shortcuts-v1.xml',
|
||||||
]
|
]
|
||||||
|
|
||||||
wl_proto_files = []
|
wl_proto_files = []
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/timerfd.h>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <poll.h>
|
|
||||||
#include <pipewire/pipewire.h>
|
#include <pipewire/pipewire.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <spa/utils/result.h>
|
#include <spa/utils/result.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/timerfd.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "xdpw.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
#include "xdpw.h"
|
||||||
|
|
||||||
enum event_loop_fd {
|
enum event_loop_fd {
|
||||||
EVENT_LOOP_DBUS,
|
EVENT_LOOP_DBUS,
|
||||||
|
@ -49,13 +49,11 @@ int main(int argc, char *argv[]) {
|
||||||
bool replace = false;
|
bool replace = false;
|
||||||
|
|
||||||
static const char *shortopts = "l:o:c:f:rh";
|
static const char *shortopts = "l:o:c:f:rh";
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {{"loglevel", required_argument, NULL, 'l'},
|
||||||
{ "loglevel", required_argument, NULL, 'l' },
|
{"config", required_argument, NULL, 'c'},
|
||||||
{ "config", required_argument, NULL, 'c' },
|
{"replace", no_argument, NULL, 'r'},
|
||||||
{ "replace", no_argument, NULL, 'r' },
|
{"help", no_argument, NULL, 'h'},
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{NULL, 0, NULL, 0}};
|
||||||
{ NULL, 0, NULL, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int c = getopt_long(argc, argv, shortopts, longopts, NULL);
|
int c = getopt_long(argc, argv, shortopts, longopts, NULL);
|
||||||
|
@ -125,6 +123,8 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
wl_list_init(&state.xdpw_sessions);
|
wl_list_init(&state.xdpw_sessions);
|
||||||
|
|
||||||
|
initShortcutsInstance(&state, &state.shortcutsInstance);
|
||||||
|
|
||||||
ret = xdpw_screenshot_init(&state);
|
ret = xdpw_screenshot_init(&state);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
logprint(ERROR, "xdpw: failed to initialize screenshot");
|
logprint(ERROR, "xdpw: failed to initialize screenshot");
|
||||||
|
@ -156,7 +156,8 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char match[1024];
|
static char match[1024];
|
||||||
snprintf(match, sizeof(match), "sender='org.freedesktop.DBus',"
|
snprintf(match, sizeof(match),
|
||||||
|
"sender='org.freedesktop.DBus',"
|
||||||
"type='signal',"
|
"type='signal',"
|
||||||
"interface='org.freedesktop.DBus',"
|
"interface='org.freedesktop.DBus',"
|
||||||
"member='NameOwnerChanged',"
|
"member='NameOwnerChanged',"
|
||||||
|
@ -174,24 +175,25 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
wl_list_init(&state.timers);
|
wl_list_init(&state.timers);
|
||||||
|
|
||||||
struct pollfd pollfds[] = {
|
struct pollfd pollfds[] = {[EVENT_LOOP_DBUS] =
|
||||||
[EVENT_LOOP_DBUS] = {
|
{
|
||||||
.fd = sd_bus_get_fd(state.bus),
|
.fd = sd_bus_get_fd(state.bus),
|
||||||
.events = POLLIN,
|
.events = POLLIN,
|
||||||
},
|
},
|
||||||
[EVENT_LOOP_WAYLAND] = {
|
[EVENT_LOOP_WAYLAND] =
|
||||||
|
{
|
||||||
.fd = wl_display_get_fd(state.wl_display),
|
.fd = wl_display_get_fd(state.wl_display),
|
||||||
.events = POLLIN,
|
.events = POLLIN,
|
||||||
},
|
},
|
||||||
[EVENT_LOOP_PIPEWIRE] = {
|
[EVENT_LOOP_PIPEWIRE] =
|
||||||
|
{
|
||||||
.fd = pw_loop_get_fd(state.pw_loop),
|
.fd = pw_loop_get_fd(state.pw_loop),
|
||||||
.events = POLLIN,
|
.events = POLLIN,
|
||||||
},
|
},
|
||||||
[EVENT_LOOP_TIMER] = {
|
[EVENT_LOOP_TIMER] = {
|
||||||
.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC),
|
.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC),
|
||||||
.events = POLLIN,
|
.events = POLLIN,
|
||||||
}
|
}};
|
||||||
};
|
|
||||||
|
|
||||||
state.timer_poll_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
state.timer_poll_fd = pollfds[EVENT_LOOP_TIMER].fd;
|
||||||
|
|
||||||
|
|
455
src/globalshortcuts/global_shortcuts.c
Normal file
455
src/globalshortcuts/global_shortcuts.c
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
#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) {
|
||||||
|
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 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;
|
||||||
|
|
||||||
|
struct globalShortcut *curr;
|
||||||
|
struct globalShortcutClient *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) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
struct globalShortcut *curr;
|
||||||
|
struct globalShortcutClient *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) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found:
|
||||||
|
|
||||||
|
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;
|
||||||
|
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) {
|
||||||
|
char *token;
|
||||||
|
sd_bus_message_read(msg, "v", "s", &token);
|
||||||
|
logprint(INFO, "dbus: option token: %s", 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);
|
||||||
|
shortcut->description = calloc(1, 1); // todo
|
||||||
|
wl_list_insert(&client->shortcuts, &shortcut->link);
|
||||||
|
|
||||||
|
// sd_bus_message_enter_container(msg, 'e', "sv");
|
||||||
|
// sd_bus_message_exit_container(msg);
|
||||||
|
sd_bus_message_skip(msg, "a{sv}");
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_handle);
|
||||||
|
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);
|
||||||
|
shortcut->description = calloc(1, 1); // todo
|
||||||
|
wl_list_insert(&client->shortcuts, &shortcut->link);
|
||||||
|
|
||||||
|
// sd_bus_message_enter_container(msg, 'e', "sv");
|
||||||
|
// sd_bus_message_exit_container(msg);
|
||||||
|
sd_bus_message_skip(msg, "a{sv}");
|
||||||
|
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);
|
||||||
|
curr->hlShortcut = hyprland_global_shortcuts_manager_v1_register_shortcut(state->shortcutsInstance.manager, curr->name, client->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);
|
||||||
|
|
||||||
|
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_handle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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) {
|
if (current->handle == handle) {
|
||||||
strncpy(current->name, title, 255);
|
strncpy(current->name, title, 255);
|
||||||
for (int i = 0; i < 255; ++i)
|
for (int i = 0; i < 255; ++i)
|
||||||
if (current->name[i] == '\"' || current->name[i] == '>' || current->name[i] == '\'')
|
if (current->name[i] == '\"' || current->name[i] == '>' || current->name[i] == '\'') current->name[i] = ' ';
|
||||||
current->name[i] = ' ';
|
|
||||||
current->name[255] = '\0';
|
current->name[255] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -57,8 +56,7 @@ void handleAppID(void *data, struct zwlr_foreign_toplevel_handle_v1 *handle, con
|
||||||
if (current->handle == handle) {
|
if (current->handle == handle) {
|
||||||
strncpy(current->clazz, app_id, 255);
|
strncpy(current->clazz, app_id, 255);
|
||||||
for (int i = 0; i < 255; ++i)
|
for (int i = 0; i < 255; ++i)
|
||||||
if (current->clazz[i] == '\"' || current->clazz[i] == '>' || current->clazz[i] == '\'')
|
if (current->clazz[i] == '\"' || current->clazz[i] == '>' || current->clazz[i] == '\'') current->clazz[i] = ' ';
|
||||||
current->clazz[i] = ' ';
|
|
||||||
current->name[255] = '\0';
|
current->name[255] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -187,8 +185,7 @@ void xdpw_wlr_frame_finish(struct xdpw_screencast_instance *cast) {
|
||||||
xdpw_pwr_enqueue_buffer(cast);
|
xdpw_pwr_enqueue_buffer(cast);
|
||||||
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
|
uint64_t delay_ns = fps_limit_measure_end(&cast->fps_limit, cast->framerate);
|
||||||
if (delay_ns > 0) {
|
if (delay_ns > 0) {
|
||||||
xdpw_add_timer(cast->ctx->state, delay_ns,
|
xdpw_add_timer(cast->ctx->state, delay_ns, (xdpw_event_loop_timer_func_t)xdpw_wlr_frame_start, cast);
|
||||||
(xdpw_event_loop_timer_func_t)xdpw_wlr_frame_start, cast);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,11 +208,9 @@ void xdpw_wlr_frame_start(struct xdpw_screencast_instance *cast) {
|
||||||
xdpw_wlr_register_cb(cast);
|
xdpw_wlr_register_cb(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_buffer_done(void *data,
|
static void wlr_frame_buffer_done(void *data, struct zwlr_screencopy_frame_v1 *frame);
|
||||||
struct zwlr_screencopy_frame_v1 *frame);
|
|
||||||
|
|
||||||
static void wlr_frame_buffer(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) {
|
||||||
uint32_t format, uint32_t width, uint32_t height, uint32_t stride) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
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,
|
static void wlr_frame_linux_dmabuf(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t format, uint32_t width, uint32_t height) {
|
||||||
struct zwlr_screencopy_frame_v1 *frame,
|
|
||||||
uint32_t format, uint32_t width, uint32_t height) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -250,8 +243,7 @@ static void wlr_frame_linux_dmabuf(void *data,
|
||||||
cast->screencopy_frame_info[DMABUF].format = format;
|
cast->screencopy_frame_info[DMABUF].format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_buffer_done(void *data,
|
static void wlr_frame_buffer_done(void *data, struct zwlr_screencopy_frame_v1 *frame) {
|
||||||
struct zwlr_screencopy_frame_v1 *frame) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -266,7 +258,8 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
|
|
||||||
// Check if announced screencopy information is compatible with pipewire meta
|
// 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) &&
|
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.width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||||
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||||
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
logprint(DEBUG, "wlroots: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
||||||
|
@ -288,8 +281,7 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
assert(cast->current_frame.xdpw_buffer);
|
assert(cast->current_frame.xdpw_buffer);
|
||||||
|
|
||||||
// Check if dequeued buffer is compatible with announced buffer
|
// Check if dequeued buffer is compatible with announced buffer
|
||||||
if ((cast->buffer_type == WL_SHM &&
|
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->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->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->width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||||
|
@ -305,8 +297,7 @@ static void wlr_frame_buffer_done(void *data,
|
||||||
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
static void wlr_frame_flags(void *data, struct zwlr_screencopy_frame_v1 *frame, uint32_t flags) {
|
||||||
uint32_t flags) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
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;
|
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,
|
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) {
|
||||||
uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -331,8 +321,7 @@ static void wlr_frame_damage(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
cast->current_frame.damage.height = height;
|
cast->current_frame.damage.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
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) {
|
||||||
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -349,8 +338,7 @@ static void wlr_frame_ready(void *data, struct zwlr_screencopy_frame_v1 *frame,
|
||||||
xdpw_wlr_frame_finish(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_frame_failed(void *data,
|
static void wlr_frame_failed(void *data, struct zwlr_screencopy_frame_v1 *frame) {
|
||||||
struct zwlr_screencopy_frame_v1 *frame) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -373,11 +361,10 @@ static const struct zwlr_screencopy_frame_v1_listener wlr_frame_listener = {
|
||||||
.damage = wlr_frame_damage,
|
.damage = wlr_frame_damage,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void hyprland_frame_buffer_done(void *data,
|
static void hyprland_frame_buffer_done(void *data, struct hyprland_toplevel_export_frame_v1 *frame);
|
||||||
struct hyprland_toplevel_export_frame_v1 *frame);
|
|
||||||
|
|
||||||
static void hyprland_frame_buffer(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 format, uint32_t width, uint32_t height, uint32_t stride) {
|
uint32_t stride) {
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -396,9 +383,8 @@ static void hyprland_frame_buffer(void *data, struct hyprland_toplevel_export_fr
|
||||||
hyprland_frame_buffer_done(cast, frame);
|
hyprland_frame_buffer_done(cast, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hyprland_frame_linux_dmabuf(void *data,
|
static void hyprland_frame_linux_dmabuf(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t format, uint32_t width,
|
||||||
struct hyprland_toplevel_export_frame_v1 *frame,
|
uint32_t height) {
|
||||||
uint32_t format, uint32_t width, uint32_t height) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -411,8 +397,7 @@ static void hyprland_frame_linux_dmabuf(void *data,
|
||||||
cast->screencopy_frame_info[DMABUF].format = format;
|
cast->screencopy_frame_info[DMABUF].format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hyprland_frame_buffer_done(void *data,
|
static void hyprland_frame_buffer_done(void *data, struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||||
struct hyprland_toplevel_export_frame_v1 *frame) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -427,7 +412,8 @@ static void hyprland_frame_buffer_done(void *data,
|
||||||
|
|
||||||
// Check if announced screencopy information is compatible with pipewire meta
|
// 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) &&
|
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.width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||||
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
cast->pwr_format.size.height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||||
logprint(DEBUG, "hyprland: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
logprint(DEBUG, "hyprland: pipewire and wlroots metadata are incompatible. Renegotiate stream");
|
||||||
|
@ -449,8 +435,7 @@ static void hyprland_frame_buffer_done(void *data,
|
||||||
assert(cast->current_frame.xdpw_buffer);
|
assert(cast->current_frame.xdpw_buffer);
|
||||||
|
|
||||||
// Check if dequeued buffer is compatible with announced buffer
|
// Check if dequeued buffer is compatible with announced buffer
|
||||||
if ((cast->buffer_type == WL_SHM &&
|
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->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->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->width != cast->screencopy_frame_info[cast->buffer_type].width ||
|
||||||
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
cast->current_frame.xdpw_buffer->height != cast->screencopy_frame_info[cast->buffer_type].height) {
|
||||||
|
@ -466,8 +451,7 @@ static void hyprland_frame_buffer_done(void *data,
|
||||||
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
fps_limit_measure_start(&cast->fps_limit, cast->framerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hyprland_frame_flags(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
static void hyprland_frame_flags(void *data, struct hyprland_toplevel_export_frame_v1 *frame, uint32_t flags) {
|
||||||
uint32_t flags) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
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;
|
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,
|
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 x, uint32_t y, uint32_t width, uint32_t height) {
|
uint32_t height) {
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -492,8 +476,8 @@ static void hyprland_frame_damage(void *data, struct hyprland_toplevel_export_fr
|
||||||
cast->current_frame.damage.height = height;
|
cast->current_frame.damage.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_frame_v1 *frame,
|
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_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) {
|
uint32_t tv_nsec) {
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -510,8 +494,7 @@ static void hyprland_frame_ready(void *data, struct hyprland_toplevel_export_fra
|
||||||
xdpw_wlr_frame_finish(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hyprland_frame_failed(void *data,
|
static void hyprland_frame_failed(void *data, struct hyprland_toplevel_export_frame_v1 *frame) {
|
||||||
struct hyprland_toplevel_export_frame_v1 *frame) {
|
|
||||||
struct xdpw_screencast_instance *cast = data;
|
struct xdpw_screencast_instance *cast = data;
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return;
|
return;
|
||||||
|
@ -524,8 +507,7 @@ static void hyprland_frame_failed(void *data,
|
||||||
xdpw_wlr_frame_finish(cast);
|
xdpw_wlr_frame_finish(cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_listener = {
|
static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_listener = {.buffer = hyprland_frame_buffer,
|
||||||
.buffer = hyprland_frame_buffer,
|
|
||||||
.buffer_done = hyprland_frame_buffer_done,
|
.buffer_done = hyprland_frame_buffer_done,
|
||||||
.linux_dmabuf = hyprland_frame_linux_dmabuf,
|
.linux_dmabuf = hyprland_frame_linux_dmabuf,
|
||||||
.flags = hyprland_frame_flags,
|
.flags = hyprland_frame_flags,
|
||||||
|
@ -536,12 +518,12 @@ static const struct hyprland_toplevel_export_frame_v1_listener hyprland_frame_li
|
||||||
void xdpw_wlr_register_cb(struct xdpw_screencast_instance *cast) {
|
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) {
|
if (cast->target.x != -1 && cast->target.y != -1 && cast->target.w != -1 && cast->target.h != -1 && cast->target.window_handle <= 0) {
|
||||||
// capture region
|
// capture region
|
||||||
cast->frame_callback = zwlr_screencopy_manager_v1_capture_output_region(
|
cast->frame_callback =
|
||||||
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output, cast->target.x,
|
zwlr_screencopy_manager_v1_capture_output_region(cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output,
|
||||||
cast->target.y, cast->target.w, cast->target.h);
|
cast->target.x, cast->target.y, cast->target.w, cast->target.h);
|
||||||
} else if (cast->target.window_handle == -1) {
|
} else if (cast->target.window_handle == -1) {
|
||||||
cast->frame_callback = zwlr_screencopy_manager_v1_capture_output(
|
cast->frame_callback =
|
||||||
cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
|
zwlr_screencopy_manager_v1_capture_output(cast->ctx->screencopy_manager, cast->with_cursor, cast->target.output->output);
|
||||||
} else {
|
} else {
|
||||||
// share window
|
// share window
|
||||||
struct SToplevelEntry *entry = toplevelEntryFromID(cast->ctx, cast->target.window_handle);
|
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->frame_callback_hyprland = hyprland_toplevel_export_manager_v1_capture_toplevel_with_wlr_toplevel_handle(
|
||||||
cast->ctx->hyprland_toplevel_manager, cast->with_cursor, entry->handle);
|
cast->ctx->hyprland_toplevel_manager, cast->with_cursor, entry->handle);
|
||||||
|
|
||||||
hyprland_toplevel_export_frame_v1_add_listener(cast->frame_callback_hyprland,
|
hyprland_toplevel_export_frame_v1_add_listener(cast->frame_callback_hyprland, &hyprland_frame_listener, cast);
|
||||||
&hyprland_frame_listener, cast);
|
|
||||||
|
|
||||||
logprint(TRACE, "hyprland: callbacks registered");
|
logprint(TRACE, "hyprland: callbacks registered");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
zwlr_screencopy_frame_v1_add_listener(cast->frame_callback,
|
zwlr_screencopy_frame_v1_add_listener(cast->frame_callback, &wlr_frame_listener, cast);
|
||||||
&wlr_frame_listener, cast);
|
|
||||||
logprint(TRACE, "wlroots: callbacks registered");
|
logprint(TRACE, "wlroots: callbacks registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_geometry(void *data, struct wl_output *wl_output,
|
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 x, int32_t y, int32_t phys_width, int32_t phys_height,
|
|
||||||
int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
||||||
struct xdpw_wlr_output *output = data;
|
struct xdpw_wlr_output *output = data;
|
||||||
output->make = strdup(make);
|
output->make = strdup(make);
|
||||||
output->model = strdup(model);
|
output->model = strdup(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_mode(void *data, struct wl_output *wl_output,
|
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) {
|
||||||
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
|
|
||||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||||
struct xdpw_wlr_output *output = data;
|
struct xdpw_wlr_output *output = data;
|
||||||
output->framerate = (float)refresh / 1000;
|
output->framerate = (float)refresh / 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_done(void *data, struct wl_output *wl_output) {
|
static void wlr_output_handle_done(void *data, struct wl_output *wl_output) { /* Nothing to do */
|
||||||
/* Nothing to do */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output,
|
static void wlr_output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { /* Nothing to do */
|
||||||
int32_t factor) {
|
|
||||||
/* Nothing to do */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_output_listener wlr_output_listener = {
|
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,
|
.scale = wlr_output_handle_scale,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 *xdg_output,
|
static void wlr_xdg_output_name(void *data, struct zxdg_output_v1 *xdg_output, const char *name) {
|
||||||
const char *name) {
|
|
||||||
struct xdpw_wlr_output *output = data;
|
struct xdpw_wlr_output *output = data;
|
||||||
|
|
||||||
output->name = strdup(name);
|
output->name = strdup(name);
|
||||||
|
@ -617,18 +591,13 @@ static const struct zxdg_output_v1_listener wlr_xdg_output_listener = {
|
||||||
.name = wlr_xdg_output_name,
|
.name = wlr_xdg_output_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wlr_add_xdg_output_listener(struct xdpw_wlr_output *output,
|
static void wlr_add_xdg_output_listener(struct xdpw_wlr_output *output, struct zxdg_output_v1 *xdg_output) {
|
||||||
struct zxdg_output_v1 *xdg_output) {
|
|
||||||
output->xdg_output = xdg_output;
|
output->xdg_output = xdg_output;
|
||||||
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener,
|
zxdg_output_v1_add_listener(output->xdg_output, &wlr_xdg_output_listener, output);
|
||||||
output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_init_xdg_output(struct xdpw_screencast_context *ctx,
|
static void wlr_init_xdg_output(struct xdpw_screencast_context *ctx, struct xdpw_wlr_output *output) {
|
||||||
struct xdpw_wlr_output *output) {
|
struct zxdg_output_v1 *xdg_output = zxdg_output_manager_v1_get_xdg_output(ctx->xdg_output_manager, 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);
|
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 *buildWindowList(struct xdpw_screencast_context *ctx) {
|
||||||
char *rolling = calloc(1, 1);
|
char *rolling = calloc(1, 1);
|
||||||
|
|
||||||
if (!ctx->wlroots_toplevel_manager)
|
if (!ctx->wlroots_toplevel_manager) return rolling;
|
||||||
return rolling;
|
|
||||||
|
|
||||||
struct SToplevelEntry *current;
|
struct SToplevelEntry *current;
|
||||||
wl_list_for_each(current, &ctx->toplevel_resource_list, link) {
|
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) {
|
for (size_t i = 0; i < strlen(rolling); ++i) {
|
||||||
if (rolling[i] == '\"')
|
if (rolling[i] == '\"') rolling[i] = ' ';
|
||||||
rolling[i] = ' ';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rolling;
|
return rolling;
|
||||||
|
@ -713,7 +680,10 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
||||||
|
|
||||||
char *windowList = buildWindowList(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);
|
free(windowList);
|
||||||
|
|
||||||
|
@ -756,8 +726,7 @@ struct xdpw_share xdpw_wlr_chooser(struct xdpw_screencast_context *ctx) {
|
||||||
|
|
||||||
free(display_name);
|
free(display_name);
|
||||||
|
|
||||||
if (!found)
|
if (!found) return res;
|
||||||
return res;
|
|
||||||
|
|
||||||
res.output = out;
|
res.output = out;
|
||||||
return res;
|
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 *xdpw_wlr_output_first(struct wl_list *output_list) {
|
||||||
struct xdpw_wlr_output *output, *tmp;
|
struct xdpw_wlr_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, output_list, link) {
|
wl_list_for_each_safe(output, tmp, output_list, link) { return output; }
|
||||||
return output;
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list,
|
struct xdpw_wlr_output *xdpw_wlr_output_find_by_name(struct wl_list *output_list, const char *name) {
|
||||||
const char *name) {
|
|
||||||
struct xdpw_wlr_output *output, *tmp;
|
struct xdpw_wlr_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, output_list, link) {
|
wl_list_for_each_safe(output, tmp, output_list, link) {
|
||||||
if (strcmp(output->name, name) == 0) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx,
|
struct xdpw_wlr_output *xdpw_wlr_output_find(struct xdpw_screencast_context *ctx, struct wl_output *out, uint32_t id) {
|
||||||
struct wl_output *out, uint32_t id) {
|
|
||||||
struct xdpw_wlr_output *output, *tmp;
|
struct xdpw_wlr_output *output, *tmp;
|
||||||
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
wl_list_for_each_safe(output, tmp, &ctx->output_list, link) {
|
||||||
if ((output->output == out) || (output->id == id)) {
|
if ((output->output == out) || (output->id == id)) {
|
||||||
|
@ -870,8 +835,7 @@ static void wlr_remove_output(struct xdpw_wlr_output *out) {
|
||||||
free(out);
|
free(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wlr_format_modifier_pair_add(struct xdpw_screencast_context *ctx,
|
static void wlr_format_modifier_pair_add(struct xdpw_screencast_context *ctx, uint32_t format, uint64_t modifier) {
|
||||||
uint32_t format, uint64_t modifier) {
|
|
||||||
struct xdpw_format_modifier_pair *fm_pair;
|
struct xdpw_format_modifier_pair *fm_pair;
|
||||||
wl_array_for_each(fm_pair, &ctx->format_modifier_pairs) {
|
wl_array_for_each(fm_pair, &ctx->format_modifier_pairs) {
|
||||||
if (fm_pair->fourcc == format && fm_pair->modifier == modifier) {
|
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);
|
logprint(TRACE, "wlroots: format %u (%lu)", fm_pair->fourcc, fm_pair->modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linux_dmabuf_handle_modifier(void *data,
|
static void linux_dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1, uint32_t format, uint32_t modifier_hi,
|
||||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1,
|
uint32_t modifier_lo) {
|
||||||
uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(TRACE, "wlroots: linux_dmabuf_handle_modifier called");
|
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,
|
.modifier = linux_dmabuf_handle_modifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void linux_dmabuf_feedback_handle_main_device(void *data,
|
static void linux_dmabuf_feedback_handle_main_device(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *device_arr) {
|
struct wl_array *device_arr) {
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_handle_main_device called");
|
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);
|
ctx->gbm = xdpw_gbm_device_create(drmDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linux_dmabuf_feedback_format_table(void *data,
|
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 zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, int fd, uint32_t size) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_format_table called");
|
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;
|
ctx->feedback_data.format_table_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linux_dmabuf_feedback_handle_done(void *data,
|
static void linux_dmabuf_feedback_handle_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_handle_done called");
|
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;
|
ctx->feedback_data.format_table_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linux_dmabuf_feedback_tranche_target_devices(void *data,
|
static void linux_dmabuf_feedback_tranche_target_devices(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *device_arr) {
|
struct wl_array *device_arr) {
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_target_devices called");
|
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,
|
static void linux_dmabuf_feedback_tranche_flags(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, uint32_t flags) {
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, uint32_t flags) {
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_flags called");
|
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_flags called");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void linux_dmabuf_feedback_tranche_formats(void *data,
|
static void linux_dmabuf_feedback_tranche_formats(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1,
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1, struct wl_array *indices) {
|
struct wl_array *indices) {
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_formats called");
|
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,
|
static void linux_dmabuf_feedback_tranche_done(void *data, struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
||||||
struct zwp_linux_dmabuf_feedback_v1 *zwp_linux_dmabuf_feedback_v1) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: linux_dmabuf_feedback_tranche_done called");
|
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,
|
.tranche_done = linux_dmabuf_feedback_tranche_done,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void wlr_registry_handle_add(void *data, struct wl_registry *reg,
|
static void wlr_registry_handle_add(void *data, struct wl_registry *reg, uint32_t id, const char *interface, uint32_t ver) {
|
||||||
uint32_t id, const char *interface, uint32_t ver) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
|
|
||||||
logprint(DEBUG, "wlroots: interface to register %s (Version: %u)", interface, ver);
|
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;
|
version = SC_MANAGER_VERSION_MIN;
|
||||||
}
|
}
|
||||||
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, version);
|
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, version);
|
||||||
ctx->screencopy_manager = wl_registry_bind(
|
ctx->screencopy_manager = wl_registry_bind(reg, id, &zwlr_screencopy_manager_v1_interface, version);
|
||||||
reg, id, &zwlr_screencopy_manager_v1_interface, version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(interface, hyprland_toplevel_export_manager_v1_interface.name) && !ctx->hyprland_toplevel_manager) {
|
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) {
|
if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
|
||||||
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, XDG_OUTPUT_MANAGER_VERSION);
|
logprint(DEBUG, "wlroots: |-- registered to interface %s (Version %u)", interface, XDG_OUTPUT_MANAGER_VERSION);
|
||||||
ctx->xdg_output_manager =
|
ctx->xdg_output_manager = wl_registry_bind(reg, id, &zxdg_output_manager_v1_interface, XDG_OUTPUT_MANAGER_VERSION);
|
||||||
wl_registry_bind(reg, id, &zxdg_output_manager_v1_interface, XDG_OUTPUT_MANAGER_VERSION);
|
|
||||||
}
|
}
|
||||||
if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
|
if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0) {
|
||||||
uint32_t version = ver;
|
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,
|
static void wlr_registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id) {
|
||||||
uint32_t id) {
|
|
||||||
struct xdpw_screencast_context *ctx = data;
|
struct xdpw_screencast_context *ctx = data;
|
||||||
struct xdpw_wlr_output *output = xdpw_wlr_output_find(ctx, NULL, id);
|
struct xdpw_wlr_output *output = xdpw_wlr_output_find(ctx, NULL, id);
|
||||||
if (output) {
|
if (output) {
|
||||||
|
@ -1164,8 +1119,7 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) {
|
||||||
|
|
||||||
// make sure our wlroots supports xdg_output_manager
|
// make sure our wlroots supports xdg_output_manager
|
||||||
if (!ctx->xdg_output_manager) {
|
if (!ctx->xdg_output_manager) {
|
||||||
logprint(ERROR, "Compositor doesn't support %s!",
|
logprint(ERROR, "Compositor doesn't support %s!", zxdg_output_manager_v1_interface.name);
|
||||||
zxdg_output_manager_v1_interface.name);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,8 +1137,7 @@ int xdpw_wlr_screencopy_init(struct xdpw_state *state) {
|
||||||
|
|
||||||
// make sure our wlroots supports screencopy protocol
|
// make sure our wlroots supports screencopy protocol
|
||||||
if (!ctx->screencopy_manager) {
|
if (!ctx->screencopy_manager) {
|
||||||
logprint(ERROR, "Compositor doesn't support %s!",
|
logprint(ERROR, "Compositor doesn't support %s!", zwlr_screencopy_manager_v1_interface.name);
|
||||||
zwlr_screencopy_manager_v1_interface.name);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1210,9 +1163,7 @@ void xdpw_wlr_screencopy_finish(struct xdpw_screencast_context *ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct xdpw_screencast_instance *cast, *tmp_c;
|
struct xdpw_screencast_instance *cast, *tmp_c;
|
||||||
wl_list_for_each_safe(cast, tmp_c, &ctx->screencast_instances, link) {
|
wl_list_for_each_safe(cast, tmp_c, &ctx->screencast_instances, link) { cast->quit = true; }
|
||||||
cast->quit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->screencopy_manager) {
|
if (ctx->screencopy_manager) {
|
||||||
zwlr_screencopy_manager_v1_destroy(ctx->screencopy_manager);
|
zwlr_screencopy_manager_v1_destroy(ctx->screencopy_manager);
|
||||||
|
|
Loading…
Reference in a new issue